#900

Migrate GitHub integration to Vercel Connect

Openblurrahwants to merge intofrom

Summary

Replaces the manually-registered GitHub App with a Vercel Connect GitHub connector. Vercel creates and manages the GitHub App; the app exchanges short-lived tokens at runtime and stores no GitHub credentials — GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY, NEXT_PUBLIC_GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, and GITHUB_WEBHOOK_SECRET are all removed in favor of a single GITHUB_CONNECTOR (UID like github/test-open-agents or scl_… id — both work).

What changed

  • Installation tokens (lib/github/installation-tokens.ts, replaces lib/github/app.ts): mintInstallationToken / withScopedInstallationOctokit keep their shape but are backed by getToken({subject: {type: "app"}, installationId}). The mint-and-revoke-per-use pattern is gone — Connect tokens are cached/shared by the SDK, so revoking one would break concurrent callers; validity buffers (5 min default, 10 min for sandbox clones) guarantee remaining lifetime instead.
  • User OAuth (lib/auth/github-provider.ts): the Better Auth github social provider becomes a genericOAuth provider via @vercel/connect/betterauth (link-only, disableImplicitSignUp). Client link calls move from linkSocial to oauth2.link with an errorCallbackURL.
  • User tokens (lib/github/token.ts): the token better-auth stores is a Connect-issued token, not a raw GitHub token, so getUserGitHubToken now exchanges via getToken({subject: {type: "user", id: accounts.accountId}}) (the Connect OIDC sub). Disconnect and the admin revoke-all action now revoke the Connect grant (revokeUserGitHubGrant) instead of calling GitHub's application-token API.
  • Webhooks (lib/github/webhook-verification.ts): /api/github/webhook now accepts Connect trigger-forwarded events verified via Vercel OIDC (createConnectWebhookVerifier) instead of HMAC. Handlers (pull_request status/archive, installation* sync) are unchanged.
  • Sandbox/git flows: untouched — the network-policy credential brokering is token-agnostic; only the token source changed.
  • apps/web drops @octokit/auth-app; @vercel/connect added.

Setup status

Connector github/test-open-agents is created, attached to the open-agents project, and GITHUB_CONNECTOR is set in the project env. Remaining: repoint NEXT_PUBLIC_GITHUB_APP_SLUG to the Connect app's github.com slug, and consider narrowing the connector's permissions in Advanced settings (it currently grants 12 write-level permissions; the app needs Contents R/W, Pull requests R/W, Metadata RO, Checks RO) plus enabling the pull_request / installation trigger event types with trigger path /api/github/webhook.

Verified against the live connector ✅

  • getToken accepts GitHub's numeric installation id as installationId (and returns it in getTokenResponse, with granted permissions in metadata) — no id-mapping column needed.
  • Minted app tokens work directly against api.github.com as installation tokens.
  • scopes / resources are accepted but do not narrow GitHub app tokens — the trust boundary stays verifyRepoAccess (user perms ∩ installation coverage), with a single seam in installation-tokens.ts to enable narrowing if Connect adds it.
  • Connect installation tokens expire after ~15 minutes (vs GitHub's usual 1 h) — hence the validity buffers.
  • Unauthorized user subjects throw UserAuthorizationRequiredError, which maps to the existing reconnect UX.

Still to verify on a preview deploy

  • The end-user link flow (oauth2.link → Connect consent → account row with Connect sub) and that GET /user/installations works with the exchanged user token.
  • Whether pull_request / installation trigger event types actually forward in beta (fallbacks: lazy PR-status refresh on session view; installation sync already runs on every connection-status poll).
  • Whether the GitHub App Setup URL is editable on the Connect-created app (fallback: app/callback stays dead-but-harmless, lazy sync covers post-install state).
  • Commit verified-badge behavior / new bot identity.

Cutover (breaking for existing users)

This is a hard cutover: everyone must re-link GitHub and re-install the new app via the existing reconnect UI. Old accounts rows for providerId='github' must be deleted manually — better-auth matches accounts by (accountId, providerId), and the Connect subject id differs from the old GitHub numeric id, so stale rows would shadow new grants forever. Run apps/web/scripts/connect-github-cutover.sql against prod at deploy time (deliberately not an auto-running migration).

Testing

  • pnpm run ci green (format, lint, typecheck, bun tests incl. rewritten token.test.ts and updated route/auto-commit/auto-pr mocks).
  • Live token probes above run with the SDK + pulled VERCEL_OIDC_TOKEN (tokens used in-process only, never logged).

🤖 Generated with Claude Code

Activity

4
vercel[bot]4mo ago

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
open-agents ReadyPreviewJul 15, 2026 8:23pm
v0-open-agents ErrorJul 15, 2026 8:23pm
socket-security[bot]4mo ago

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

DiffPackageSupply Chain
Security
VulnerabilityQualityMaintenanceLicense
npm/​@​vercel/​connect@​0.3.3

View full report