Skip to content
Docs

Vercel KMS Authentication

KMS authorizes requests differently depending on what you are doing. Signing is authorized with a short-lived deployment OIDC token, management operations are authorized with a Vercel access token, and relying parties verify signatures against the issuer's published JWKS without authenticating at all.

Signing requests are authorized with a Vercel OIDC token in the Authorization: Bearer <token> header. Inside a Vercel Function, the deployment's OIDC token is used automatically, so you do not manage any credentials yourself. To learn more about the token, see OIDC federation.

The @vercel/kms SDK resolves the function's OIDC token for you through @vercel/oidc. Because the token is resolved at call time, call signJWT and signMessage inside an active request context, not at the module top level.

Management operations, such as staging or activating a key during rotation, are authorized with a Vercel access token rather than a deployment OIDC token. Pass it in the Authorization: Bearer <token> header:

curl -X POST \
  "https://api.vercel.com/v1/kms/issuers/f47ac10b-58cc-4372-a567-0e02b2c3d479/keys" \
  -H "authorization: Bearer $VERCEL_TOKEN" \
  -H "content-type: application/json" \
  -d '{ "activation": "automatic" }'

A policy is the rule that authorizes signing for an issuer. KMS supports two policy kinds:

  • Project grant (project-grant): lets a Vercel deployment sign with its OIDC token, scoped to a project and its environments. It confers signing access only, never provisioning.
  • Connect grant (connex-grant): lets Vercel Connect provision and sign with the issuer on behalf of your team, identified by a Connect client ID.

A policy can also define KMS-owned tokenClaims, and an issuer can define a claims schema that validates every token it signs. See Claims.

Relying parties verify signatures against the issuer's public keys without authenticating. Every issuer publishes its public keys so verification needs no contact with Vercel:

  • Issuer URL: https://kms.vercel.com/<issuerId>
  • JWKS: https://kms.vercel.com/<issuerId>/jwks.json
  • OpenID configuration: https://kms.vercel.com/<issuerId>/.well-known/openid-configuration

KMS sets the JWT kid header on each signature, so a verifier picks the right key from the JWKS automatically. This example uses jose:

verify.ts
import { createRemoteJWKSet, jwtVerify } from 'jose';
 
const issuer = 'https://kms.vercel.com/f47ac10b-58cc-4372-a567-0e02b2c3d479';
const jwks = createRemoteJWKSet(new URL(`${issuer}/jwks.json`));
 
const { payload } = await jwtVerify(token, jwks, { issuer });
Last updated August 18, 2026

Was this helpful?

supported.