Authenticate Slack, GitHub, and Linear adapters with Vercel Connect — short-lived runtime tokens for outbound calls and OIDC-verified inbound webhooks, with no stored provider secrets.
Vercel Connect lets your bot use a registered connector for adapter authentication instead of storing long-lived provider secrets. You register a connector once, link it to your project and environments, and your code requests scoped, short-lived tokens at runtime.
The @vercel/connect/chat subpath ships a helper per platform that you spread into the matching create*Adapter factory:
connectSlackAdapterconnectGitHubAdapterconnectLinearAdapter
Each helper wires both directions of traffic:
- Outbound (your bot calls the provider API) — a function-form token field that resolves a fresh, short-lived token per call via
getToken. - Inbound (the provider calls your bot) — a
webhookVerifierthat validates the Vercel OIDC token Connect attaches to trigger-forwarded webhooks, replacing the provider's native signature check.
Vercel Connect is in beta. Features and behavior, including available connectors and trigger forwarding, may change before general availability.
@vercel/connect reads the deployment's OIDC token automatically. For local development, run vercel link followed by vercel env pull to download a short-lived token into .env.local.
| Adapter | Helper | Outbound field |
|---|---|---|
| Slack | connectSlackAdapter | botToken |
| GitHub | connectGitHubAdapter | installationToken |
| Linear | connectLinearAdapter | accessToken |
Each helper accepts (connector, params?, options?), where params is the getToken parameters minus subject (pinned to { type: "app" }), letting you pass through installationId, scopes, or validityBufferMs.
- Create a connector for the provider in the Vercel dashboard or with the CLI, enabling trigger forwarding so inbound webhooks reach your project:
vercel connect create slack --name acme-slack --triggers- Attach your project and register your Chat SDK webhook route (
/api/webhooks/{platform}) as the trigger destination:
vercel connect attach slack/acme-slack \
--project my-bot --environment production \
--triggers --trigger-path /api/webhooks/slack- Pull a development token locally (deployments get
VERCEL_OIDC_TOKENautomatically):
vercel link
vercel env pullSpread the helper into the adapter factory. The webhook route is unchanged — Connect forwards verified events to the same handler.
import { Chat } from "chat";
import { createSlackAdapter } from "@chat-adapter/slack";
import { createRedisState } from "@chat-adapter/state-redis";
import { connectSlackAdapter } from "@vercel/connect/chat";
export const bot = new Chat({
userName: "mybot",
adapters: {
slack: createSlackAdapter({
...connectSlackAdapter("slack/acme-slack"),
}),
},
state: createRedisState(),
});Replace slack/acme-slack with your connector UID from the Connect dashboard or vercel connect list. Omit signingSecret / SLACK_SIGNING_SECRET when using the helper — the OIDC webhookVerifier is the freshness boundary.
GitHub
import { createGitHubAdapter } from "@chat-adapter/github";
import { connectGitHubAdapter } from "@vercel/connect/chat";
createGitHubAdapter({
...connectGitHubAdapter("github/acme-github"),
userName: "my-bot[bot]",
});installationToken is the installation access token a GitHub App would normally mint via its private-key JWT exchange — the adapter uses it directly and skips that exchange.
Linear
import { createLinearAdapter } from "@chat-adapter/linear";
import { connectLinearAdapter } from "@vercel/connect/chat";
createLinearAdapter({
...connectLinearAdapter("linear/acme-linear"),
mode: "agent-sessions",
});Use mode: "agent-sessions" for app-actor installs. For outbound calls outside webhook handling (cron jobs, workflows), wrap them in withInstallation() so a request-scoped client is bound:
await linear.withInstallation("org-id", async () => {
await linear.postMessage("linear:issue-id", "Hello from a background job");
});Each helper attaches a default verifier that matches the deployment's project and environment automatically (projectId defaults to VERCEL_PROJECT_ID, environment to VERCEL_TARGET_ENV then VERCEL_ENV), so production, preview, and development each accept only their own tokens. Verification fails closed — if those values are absent, every request is rejected, and the issuer is pinned to https://oidc.vercel.com.
To add constraints (for example to accept multiple environments), build a verifier with createConnectWebhookVerifier and override the field:
import {
connectSlackAdapter,
createConnectWebhookVerifier,
} from "@vercel/connect/chat";
createSlackAdapter({
...connectSlackAdapter("slack/acme-slack"),
webhookVerifier: createConnectWebhookVerifier({
environment: ["production", "preview"],
}),
});Avoid hardcoding environment: "production" unless you only forward to production — it would reject preview and development deployments.
- App-scoped tokens. The helpers act as the application itself (
subject: { type: "app" }). End-user OAuth is a separate concern. - Freshness and replay. OIDC verification replaces each provider's native signature (and timestamp) check, so request freshness relies on the short-lived OIDC token's expiry rather than a signed timestamp, and there is no built-in delivery de-duplication. Keep your webhook handlers idempotent.
- Socket Mode is incompatible. Connect trigger forwarding is HTTP-only; it doesn't apply to the Slack adapter's Socket Mode.
- Testing. Connect forwards to deployed URLs, not
localhost— test against a preview or development deployment.





























