Guide

Tokens and Authentication

Authenticate GitHub tools with fine-grained PATs or Vercel Connect, map token permissions to each preset and apply least privilege.

Every tool call hits the GitHub API with the token you provide. Scoping that token correctly is the first line of defense. You have two main options: a fine-grained personal access token you manage yourself, or short-lived tokens minted by Vercel Connect.

Align GitHub PAT with tool presets

Create a fine-grained token

Fine-grained personal access tokens let you restrict access per repository and per permission category. This is the recommended type for any production assistant.

  1. Go to github.com/settings/personal-access-tokens/new
  2. Select only the repositories your agent needs
  3. Enable permissions based on the preset you plan to use (see matrix below)

Map permissions to presets

PresetRepository accessContentsPull requestsIssuesDiscussionsActionsChecks/StatusesAdministration
repo-explorerselected reposreadreadreadreadreadreadnone
code-reviewselected reposreadread (or write for comments/reviewer requests)nonenonenonereadnone
issue-triageselected reposreadnonewritenonenonenonenone
ci-opsselected reposreadnonenonenonewritereadnone
security-auditselected reposreadreadwrite (to report findings)nonereadreadnone
release-managerselected reposwrite (for release creation)readnonenonewrite (if triggering pipelines)nonenone
discussion-moderatorselected reposreadnonewrite (when linking issues)writenonenonenone
notification-inboxselected reposreadreadreadnonenonenonenone
pr-authorselected reposwritewritenonenonenonenonenone
maintainerselected reposwritewritewritewritewritereadwrite (for repo creation and forking)

Reactions (listIssueReactions, addIssueReaction, listCommentReactions, addCommentReaction) are covered by the Issues permission and need no scope of their own.

repo-explorer and maintainer also include gist read (and, for maintainer, write) tools. Gists aren't tied to a repository. GitHub only grants gist access to GitHub App user access tokens, never installation tokens, so give the PAT the "Gists" account permission separately, and expect gist tools to fail over Vercel Connect (see below).

notification-inbox and maintainer include listNotifications and markNotificationRead. Notifications belong to a user rather than a repository, so they need the "Notifications" account permission on the PAT and, like gists, fail with a Connect-minted installation token.

Releases are covered by the Contents permission on GitHub Apps: repo-explorer, release-manager, and maintainer need no separate scope for listReleases, getLatestRelease, or getRelease.

Mint tokens with Vercel Connect

For agents deployed on Vercel, Vercel Connect replaces long-lived PATs entirely. You attach a GitHub connector (a Vercel-managed GitHub App) to your project, and your server code requests a short-lived, scoped token at runtime, with no secret to store, rotate, or leak.

First-class helper: use @github-tools/sdk/connect to derive scopes from your preset automatically. See the Vercel Connect guide for connectGithubTools and connectGithubToken.

Create a GitHub connector

Create a connector from the Vercel dashboard (or vercel connect in the CLI) with the type github, then install it on the GitHub organization or user account your agent needs, selecting the repositories to expose.

Link the connector to the Vercel project that runs your agent. On Vercel, the SDK authenticates automatically with the deployment's OIDC token. For local development, run vercel link then vercel env pull to get a development OIDC token.

Request a token at runtime

Install @vercel/connect and call getToken with the permissions your preset needs, then pass the result as token. Prefer the connect subpath when you want preset-derived scopes without maintaining a scope list:

connect-tools.ts
import { connectGithubTools } from '@github-tools/sdk/connect'
import { generateText } from 'ai'

const { text } = await generateText({
  model: 'anthropic/claude-sonnet-4.6',
  tools: connectGithubTools('github/my-connector', { preset: 'code-review' }),
  prompt: 'Summarize the open PRs on my-org/my-repo.',
})

Manual getToken (full control over every parameter): pass a lazy provider so minting happens at tool execution, not at import/build time:

lazy-token.ts
import { getToken } from '@vercel/connect'
import { createGithubTools } from '@github-tools/sdk'

const tools = createGithubTools({
  token: () => getToken('github/my-connector', {
    subject: { type: 'app' },
    scopes: ['contents:read', 'pull_requests:read'],
  }),
  preset: 'code-review',
})
Avoid top-level await getToken(...) in modules that are imported at build time, especially eve agent/extensions/*.ts (or agent/tools/*.ts for the deprecated direct import) exports. Minting needs the Vercel OIDC header and only exists at request/runtime. Prefer the extension's connector option, connectGithubTools / connectGithubToken, or a token: () => getToken(...) provider as above.

The provider is invoked at each tool execution, so short-lived tokens stay fresh across a long agent run. Note that in durable workflows the resolved token string is captured in the step arguments. A retried step reuses the token it was first invoked with rather than requesting a new one.

Call getToken per request rather than caching the string yourself. The SDK keeps an in-process cache and refreshes tokens as they approach expiry. For multi-tenant connectors (one connector installed on several GitHub organizations), pass installationId to target a specific installation. When you need a different connector per environment or tenant rather than the same connector with a different installation, connectGithubTools / connectGithubToken also accept a () => string | Promise<string> resolver in place of a connector name, see Vercel Connect: dynamic connector selection.

Why Connect over a PAT

Fine-grained PATVercel Connect
LifetimeUntil expiry/revocationShort-lived, auto-refreshed
StorageEnv var / secret managerNothing to store, minted at runtime
ScopingSet once at creationPer-request scopes and repositories
Multi-tenantOne token per orgOne connector, many installations
RotationManualAutomatic
Using eve? Pass connector directly to the eve extension mount config, no separate import needed:
agent/extensions/github.ts
import githubExtension from '@github-tools/eve-extension'

export default githubExtension({ connector: 'github/my-connector', preset: 'maintainer' })
(For the deprecated direct import, connectGithubTools from @github-tools/sdk/connect/eve still works the same way.)

Apply least-privilege step by step

Start with read-only

Enable only contents: read and use preset: 'repo-explorer'.

Validate in staging

Run the agent against a test repository and review all tool calls before adding write scopes.

Add writes for approved operations

Enable write permissions only for the specific families you need, and combine with approval control.

Safest baseline: fine-grained token (or Connect-minted token) + narrow preset + requireApproval: true.

External references