# How to Configure GitHub App Integration for Open Agents: Complete Setup Guide

> Configure GitHub App integration for Open Agents. Securely add repository and PR permissions via Vercel env variables and implement the OAuth flow for seamless access.

- Repository: [Vercel Labs/open-agents](https://github.com/vercel-labs/open-agents)
- Tags: how-to-guide
- Published: 2026-04-16

---

**Configure GitHub App integration for Open Agents by creating a public GitHub App with repository and pull request permissions, adding the Client ID, Client Secret, and Private Key to your Vercel environment variables, and implementing the `/installations/select_target` OAuth flow with CSRF state validation.**

Open Agents uses a **GitHub App** (not a standalone OAuth app) to securely read, clone, push, and open pull requests on user repositories. This guide covers the complete configuration process based on the actual implementation in the `vercel-labs/open-agents` repository, from app creation to handling the OAuth callback and syncing installations.

## Create the GitHub App

Start by registering a new GitHub App in your developer settings. The repository documentation emphasizes several critical configuration choices that differ from standard OAuth setups.

### Required Permissions and Settings

Configure the following in your GitHub App settings:

- **Permissions**: Enable read/write access for **Contents**, **Pull requests**, **Metadata**, and **Repository administration** (required for fork creation).
- **Webhook URL**: Set to `https://your-deployment-url/api/github/webhook` to receive installation events.
- **Public App**: Navigate to **Danger Zone** and click **Make public**. The Open Agents documentation warns that private apps hide the organization picker, preventing installations on organizations 【lessons‑learned:100】.
- **Disable OAuth During Install**: Uncheck **"Request user authorization (OAuth) during installation"** to prevent redirect loops for already-authorized users 【lessons‑learned:99】.

### Save Credentials

After creation, save three values required for the next step:

1. **Client ID** (found in App settings)
2. **Client Secret** (generate one if not present)
3. **Private Key** (generate and download the `.pem` file)

## Configure Environment Variables in Vercel

Add the GitHub App credentials to your Vercel project environment variables. The repository expects these exact variable names as documented in the README 【README:219-L220】:

```text
NEXT_PUBLIC_GITHUB_CLIENT_ID=your-client-id
GITHUB_CLIENT_SECRET=your-client-secret
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA...
...
-----END RSA PRIVATE KEY-----"

```

Store the private key as a **Secret** in Vercel to preserve line breaks. Redeploy the application after adding these variables to ensure the serverless functions receive the updated configuration.

## Generate the Install URL

Open Agents requires using the `/installations/select_target` endpoint rather than the standard `/installations/new` path. The latter silently redirects to the user's personal installation page, skipping the organization picker 【lessons‑learned:101】.

The `buildGitHubInstallUrl` function in [`apps/web/lib/github/client.ts`](https://github.com/vercel-labs/open-agents/blob/main/apps/web/lib/github/client.ts) constructs the proper URL:

```typescript
import { generateCSRFState } from '@/lib/csrf';

export function buildGitHubInstallUrl(redirectAfter: string): string {
  const base = "https://github.com/apps/open-agents/installations/select_target";
  const params = new URLSearchParams({
    state: generateCSRFState(),  // Stored server-side for validation
    redirect_uri: `${process.env.NEXT_PUBLIC_BASE_URL}/api/github/callback`,
  });
  return `${base}?${params.toString()}`;
}

```

Use this URL for your "Connect GitHub" button in the UI.

## Handle the OAuth Callback Securely

When GitHub redirects to your callback endpoint after authorization, implement strict security checks. The repository explicitly warns that failure to validate the `state` parameter opens a CSRF vulnerability 【lessons‑learned:102】.

Create the API route at [`pages/api/github/callback.ts`](https://github.com/vercel-labs/open-agents/blob/main/pages/api/github/callback.ts):

```typescript
import { exchangeCodeForToken } from '@/lib/github/client';
import { verifyState } from '@/lib/csrf';
import { updateGitHubAccountTokens } from '@/lib/db/accounts';
import { syncGitHubInstallations } from '@/lib/github/installations-sync';

export default async function handler(req, res) {
  const { code, state } = req.query;
  
  // Critical: Validate CSRF state before token exchange
  if (!verifyState(state, req)) {
    return res.status(400).send('Invalid state parameter');
  }

  try {
    const tokenInfo = await exchangeCodeForToken(code as string);
    
    // Persist encrypted tokens
    await updateGitHubAccountTokens(req.session.userId, {
      accessToken: tokenInfo.access_token,
      refreshToken: tokenInfo.refresh_token,
      expiresAt: Date.now() + tokenInfo.expires_in * 1000,
    });

    // Sync accessible repositories immediately
    await syncGitHubInstallations(req.session.userId, tokenInfo.installation_id);
    
    res.redirect('/dashboard');
  } catch (error) {
    res.status(500).send('Authentication failed');
  }
}

```

## Sync Installations to Populate Database

After authentication, synchronize the list of repositories the app can access. The sync logic resides in [`apps/web/lib/github/installations-sync.ts`](https://github.com/vercel-labs/open-agents/blob/main/apps/web/lib/github/installations-sync.ts).

Important implementation details from the source:

- **Paginate with `per_page=100`** and fetch all pages before pruning old database rows to avoid race conditions 【lessons‑learned:103】.
- **Invoke sync after both OAuth-only callbacks and normal installs** to ensure the database stays current 【lessons‑learned:104】.

```typescript
// Example invocation after successful callback
await syncGitHubInstallations(userId, installationId);

```

## Repository Access and PR Creation Flow

When the agent needs to push changes, Open Agents implements a credential brokering system with automatic fallback strategies.

### The Access Flow

1. **Retrieve User Token**: Call `getUserGitHubToken` to obtain a valid token, automatically refreshing if expired.
2. **Create Sandbox**: Initialize a sandbox with the token brokered via `buildGitHubCredentialBrokeringPolicy` in [`packages/sandbox/vercel/sandbox.ts`](https://github.com/vercel-labs/open-agents/blob/main/packages/sandbox/vercel/sandbox.ts).
3. **Push Strategy**: Attempt to push directly. If the token lacks write permission, the SDK falls back to **fork-and-PR** mode.

### Handling Edge Cases

The repository documents specific error handling for GitHub API edge cases:

- **403 Resource not accessible by integration**: When fork creation fails with this error, display a manual fork guide instead of crashing 【lessons‑learned:108】.
- **403 on PR creation**: If the app cannot create the PR, generate a pre-filled compare URL (`/compare/branch...`) for the user to complete manually 【lessons‑learned:110‑111】.

## Summary

- **Create a public GitHub App** with read/write permissions for Contents, Pull requests, and Repository administration, ensuring you disable OAuth during installation to prevent redirect loops.
- **Configure three environment variables** in Vercel: `NEXT_PUBLIC_GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, and `GITHUB_APP_PRIVATE_KEY`.
- **Use `/installations/select_target`** for the install URL to ensure the organization picker appears, validating the CSRF `state` parameter in the callback handler.
- **Sync installations immediately** after authentication using `syncGitHubInstallations` to populate the database with accessible repositories.
- **Implement fallback workflows** for 403 errors during fork and PR creation to handle repositories where the app lacks direct write access.

## Frequently Asked Questions

### What permissions does the GitHub App need for Open Agents?

The GitHub App requires read/write access to **Contents** (for cloning and pushing), **Pull requests** (for creating PRs), **Metadata** (for reading repository info), and **Repository administration** (for creating forks when direct push is unavailable). These permissions are set in the GitHub App settings under Repository permissions.

### Why must the GitHub App be set to public rather than private?

A private GitHub App hides the organization picker during installation, preventing users from installing the app on their organization repositories. According to the Open Agents documentation, making the app public enables the org picker, allowing installations on both personal and organization accounts.

### How does Open Agents handle repositories where it doesn't have write access?

When the agent attempts to push to a repository without write permission, the SDK automatically falls back to a fork-and-PR workflow. If fork creation fails with a 403 error, the application surfaces a manual fork guide. If PR creation fails, it generates a pre-filled compare URL for the user to complete manually.