Vercel KMS SDK Reference
The @vercel/kms package wraps the KMS signing API and fetches the function's OIDC token through @vercel/oidc, so you sign without managing credentials.
pnpm i @vercel/kmsSigns a JWT for an issuer using its managed signing key and resolves to { token, keyId, algorithm, fingerprint }. token is the compact JWT, keyId matches the JWKS kid, algorithm is the signing key's algorithm, and fingerprint is the SHA-256 fingerprint of the signing key's public key (SHA256:<base64>). KMS sets the iat, nbf, and exp claims.
import { signJWT } from '@vercel/kms';
export async function GET() {
const { token } = await signJWT({
issuerId: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
claims: { sub: 'user_123', scope: 'read:data' },
ttl: 300, // seconds
});
return Response.json({ token });
}| Parameter | Type | Required | Description |
|---|---|---|---|
issuerId | string | Yes | The ID of the issuer to sign with. |
claims | Record<string, unknown> | No | Custom claims to include in the token payload. |
headers | Record<string, unknown> | No | Additional headers to include in the token header. |
ttl | number | null | No | Token lifetime in seconds. Defaults to 300 seconds. |
token | string | No | An explicit Vercel OIDC token to authenticate with. When omitted, the function's OIDC token is fetched automatically via @vercel/oidc. |
region | string | No | The KMS region to call. See Region resolution. |
baseUrl | string | No | Overrides the API base URL. Takes precedence over region. |
Signs a JWT for an issuer and resolves to the compact JWT string. Its options are the same as signJWT's. Use signJWT instead.
Signs an arbitrary message and resolves to { signature, keyId, algorithm, fingerprint }. signature is a Uint8Array of the raw signature bytes, keyId matches the JWKS kid, algorithm is the signing key's algorithm, and fingerprint is the SHA-256 fingerprint of the signing key's public key (SHA256:<base64>). Pass the message as a string (treated as UTF-8) or a Uint8Array of raw bytes. @vercel/kms base64-encodes it before sending. Use signJWT to mint JWTs. Message signing is rejected when the issuer's policy defines tokenClaims or the issuer defines a claims schema.
This example signs the HTTP method, URL, and body as a single message, then sends the POST with the signature in the x-signature header:
import { signMessage } from '@vercel/kms';
export async function GET() {
const method = 'POST';
const url = 'https://example.com/data';
const body = JSON.stringify({ orderId: 'ord_123' });
const message = `${method}\n${url}\n${body}`;
const { signature, keyId } = await signMessage({
issuerId: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
message,
});
const response = await fetch(url, {
method,
headers: {
'content-type': 'application/json',
'x-signature': Buffer.from(signature).toString('base64'),
'x-key-id': keyId,
},
body,
});
return Response.json({ ok: response.ok });
}The verifier must reconstruct the same message bytes you signed. Use keyId to select the key from the issuer's JWKS after rotation, then verify the signature with that public key using crypto.verify or Web Crypto.
| Parameter | Type | Required | Description |
|---|---|---|---|
issuerId | string | Yes | The ID of the issuer to sign with. |
message | string | Uint8Array | Yes | The message to sign. A string is signed as UTF-8 bytes. |
token | string | No | An explicit Vercel OIDC token to authenticate with. When omitted, the function's OIDC token is fetched automatically via @vercel/oidc. |
region | string | No | The KMS region to call. See Region resolution. |
baseUrl | string | No | Overrides the API base URL. Takes precedence over region. |
The client calls the regional KMS host. It reads the region from the region option, then the VERCEL_REGION environment variable, and produces https://api-<region>.vercel.com/v1. When no region is available, it falls back to the global https://api.vercel.com/v1 host.
You do not need the SDK to sign. Send an authenticated POST to the KMS signing endpoints with any HTTP client. The signing endpoints authorize the request with a Vercel OIDC token in the Authorization: Bearer <token> header. Inside a Vercel Function, read the deployment's OIDC token with @vercel/oidc:
import { getVercelOidcToken } from '@vercel/oidc';
const issuerId = 'f47ac10b-58cc-4372-a567-0e02b2c3d479';
export async function GET() {
const oidcToken = await getVercelOidcToken();
const region = process.env.VERCEL_REGION;
const baseUrl = region
? `https://api-${region}.vercel.com/v1`
: 'https://api.vercel.com/v1';
const response = await fetch(
`${baseUrl}/kms/issuers/${issuerId}/sign/token`,
{
method: 'POST',
headers: {
authorization: `Bearer ${oidcToken}`,
'content-type': 'application/json',
},
body: JSON.stringify({
claims: { sub: 'user_123', scope: 'read:data' },
ttl: 300, // seconds, defaults to 300
}),
},
);
const { token } = await response.json();
return Response.json({ token });
}The token endpoint returns { "token": "<compact JWT>" }.
To sign a message, POST to /v1/kms/issuers/<issuerId>/sign/message with a base64-encoded message. The endpoint returns { signature, keyId, algorithm }, with signature as standard-base64 of the raw signature bytes:
curl -X POST \
"https://api.vercel.com/v1/kms/issuers/f47ac10b-58cc-4372-a567-0e02b2c3d479/sign/message" \
-H "authorization: Bearer $VERCEL_OIDC_TOKEN" \
-H "content-type: application/json" \
-d "{\"message\": \"$(printf 'hello world' | base64)\"}"Was this helpful?