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

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】:

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 constructs the proper URL:

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:

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.

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】.
// 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.
  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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →