Skip to content

SDK Reference

@vercel/connect is the TypeScript SDK for calling Vercel Connect from your app. It authenticates with your Vercel deployment's OIDC token and exchanges it for provider tokens through the Vercel API. SDK methods that make API requests are subject to rate limits.

terminal
pnpm add @vercel/connect

The SDK has one runtime dependency, @vercel/oidc, which reads VERCEL_OIDC_TOKEN from the environment.

In a Vercel deployment, the SDK reads VERCEL_OIDC_TOKEN automatically. For local development, run vercel link followed by vercel env pull to download a development token into .env.local. The token is short-lived; re-run vercel env pull if you see authentication errors.

To override the token explicitly, pass options.vercelToken:

app/lib/explicit-token.ts
import { getToken } from '@vercel/connect';
 
const token = await getToken(
  'slack/acme-slack',
  { subject: { type: 'app' } },
  { vercelToken: process.env.MY_VERCEL_TOKEN },
);

See Authentication for the full caller-to-Vercel-Connect story.

Returns the access token string. Use when you just need the token to put in an Authorization header.

signature
function getToken(
  connector: string,
  params: ConnectTokenParams,
  options?: ConnectOptions,
): Promise<string>;

Minimal example:

app/lib/post-to-slack.ts
import { getToken } from '@vercel/connect';
 
const token = await getToken('slack/acme-slack', {
  subject: { type: 'app' },
  scopes: ['chat:write'],
});
 
await fetch('https://slack.com/api/chat.postMessage', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ channel: 'C123', text: 'hello' }),
});

This omits installationId and falls back to the connector's default installation, which is the predominant case (a private app installed in a single workspace). Pass installationId explicitly only for multi-tenant connectors where you need to address a specific installation. See Installations.

Returns the full response: the token, its expiry, the connector identity, and provider metadata. Use when your app needs more than the raw string, for example to display the connected workspace name or to decide whether to surface a re-authorize button.

signature
function getTokenResponse(
  connector: string,
  params: ConnectTokenParams,
  options?: ConnectOptions,
): Promise<ConnectTokenResponse>;

Minimal example:

app/lib/inspect-token.ts
import { getTokenResponse } from '@vercel/connect';
 
const response = await getTokenResponse('slack/acme-slack', {
  subject: { type: 'app' },
});
 
console.log(response.connector.uid);
console.log(response.tenantId);
console.log(new Date(response.expiresAt).toISOString());

Returns the connector's stable public metadata and provider-specific configuration. Use it when your app needs connector setup values in addition to a runtime token, such as a Snowflake account identifier.

signature
function getConnectorMetadata(
  connector: string,
  options?: ConnectOptions,
): Promise<ConnectorMetadata>;
app/lib/snowflake.ts
import { getConnectorMetadata } from '@vercel/connect';
 
const connector = await getConnectorMetadata('snowflake/analytics');
const accountIdentifier = connector.vendor.accountIdentifier as string;
 
console.log(connector.name);
console.log(accountIdentifier);

The calling project and environment must be linked to the connector, just as they must be for getToken.

FieldTypeRequiredDescription
subjectConnectTokenSubject (see below)yesWho the token represents. See Tokens.
installationIdstringnoWhich tenant the token is for. Pass '*' for a cross-installation token where the connector supports it. See Installations.
audiencestring[]noProvider audience claim. Used when the provider requires a specific audience in the issued token.
scopesstring[]noProvider scope strings (chat:write, repo:read, etc.). Pass ['*'] to request the connector's default scopes for the selected subject type.
resourcesstring[]noResource indicators that narrow the token to a specific provider resource (channel, repo, record set). SDK-only.
authorizationDetailsArray<{ type: string } & Record<string, unknown>>noRich authorization requests, when the provider supports them. SDK-only.
validityBufferMsnumbernoRefresh the token if it expires within this many milliseconds. Defaults to 30000 (30 seconds).

A discriminated union with three variants:

@vercel/connect
type ConnectTokenSubject =
  | { type: 'app' }
  | { type: 'user'; id: string; issuer?: string }
  | {
      type: 'jwt-bearer';
      sub: string;
      iss?: string;
      aud?: string;
      additionalClaims?: Record<string, unknown>;
    };
VariantRequired fieldsOptional fields
appnonenone
useridissuer (the OIDC issuer of the user id, when not the default)
jwt-bearersubiss (defaults to the connector's OAuth client id), aud (defaults to the connector's OAuth token endpoint), additionalClaims
FieldTypeDescription
tokenstringThe access token to send to the provider.
tokenIdstring | undefinedPer-issuance identifier (stk_…) for correlating the token with Connect observability and usage data.
expiresAtnumberToken expiration as a Unix timestamp in milliseconds.
connector.idstringOpaque internal identifier for the connector.
connector.uidstringHuman-readable connector identifier (the same string you passed as the first arg).
connector.typestringThe connector type (slack, github, linear, microsoft-entra, oauth, snowflake, salesforce, api-key, custom).
namestring | undefinedHuman-readable connector or installation name, when known.
installationIdstring | undefinedThe installation this token was issued against, when applicable.
tenantIdstring | undefinedProvider's own tenant identifier (Slack team ID, GitHub org ID, Microsoft tenant GUID).
externalSubjectstring | undefinedThe subject identifier at the provider (for example, the Slack user ID for a user-subject token).
metadataRecord<string, unknown> | undefinedDriver-specific metadata stored during OAuth (varies by provider).
claimsRecord<string, unknown> | undefinedAllow-listed claims propagated from the upstream provider token.
FieldTypeDescription
idstringOpaque internal connector identifier.
uidstringHuman-readable connector identifier.
namestringConnector display name.
typestringConnector type, such as snowflake or oauth.
servicestringService the connector integrates with.
clientUrlstring | undefinedFully qualified service URL, when Vercel Connect can derive it.
createdAtnumberCreation time as a Unix timestamp in milliseconds.
updatedAtnumberLast update time as a Unix timestamp in milliseconds.
vendorRecord<string, unknown>Provider-specific public configuration stored on the connector.
FieldTypeDescription
vercelTokenstringOverride the OIDC token the SDK reads from the environment. Useful for tests and non-Vercel runtimes.
forceRefreshbooleanFor getToken and getTokenResponse, bypass the in-process cache and revalidate the grant with Vercel Connect.

Revokes the provider grant for a connector subject and clears the SDK's in-process token cache. Provider support for revocation varies; see Revocation.

Rate limit: 50 requests per minute per team (write operation).

app/lib/disconnect.ts
import { revokeToken } from '@vercel/connect';
 
await revokeToken('oauth/linear', {
  subject: { type: 'user', id: 'user_123' },
});

Removes one cached token without revoking its provider grant. Pass the same connector and complete request parameters that you used for getToken or getTokenResponse. The next request for that cache entry fetches a fresh token.

app/lib/retry-token.ts
import { deleteTokenCacheEntry, getToken } from '@vercel/connect';
 
const params = {
  subject: { type: 'app' as const },
  scopes: ['chat:write'],
};
 
let token = await getToken('slack/acme-slack', params);
 
// If Slack rejects this token with a 401:
deleteTokenCacheEntry('slack/acme-slack', params);
token = await getToken('slack/acme-slack', params);

The SDK maintains an in-process LRU cache with a maximum of 100 entries, keyed by the connector and the full request params. Cached tokens are reused on subsequent calls until they fall inside the validityBufferMs window, at which point the next call fetches a fresh one.

Pass { forceRefresh: true } in ConnectOptions to bypass the cache for a request. Use deleteTokenCacheEntry when you only need to discard one rejected token while preserving normal caching for future calls.

The SDK throws typed error classes you can match on with instanceof:

ErrorCause
NoValidTokenErrorThe connector exists but cannot produce a token for this request. The grant may have been revoked at the provider.
UserAuthorizationRequiredErrorThe request used a { type: 'user' } subject and that user has not authorized the connector. Surface a "connect your account" UI.
ConnectorInstallationRequiredErrorThe connector type requires an installation and none matches the request. Surface an install link.
ConnectorNotFoundErrorThe team has no connector registered under the given uid.
ClientNotLinkedToProjectErrorThe calling project is not linked to this connector. See Project links.
ClientNotEnabledForEnvironmentErrorThe link exists but does not include the environment the OIDC token was issued for.

Most SDK calls have a vercel connect CLI equivalent. The CLI supports --subject, --installation-id, and --scopes. The SDK additionally supports resources and authorizationDetails, which are not exposed through the CLI. The CLI supports --triggers on vercel connect attach, which has no SDK equivalent.

  • Quickstart: Wire getToken into a working integration in four steps.
  • Tokens: How a token request is shaped and what each field does.
  • Authentication: What the OIDC token carries and how the API checks it.
Last updated August 26, 2026

Was this helpful?