Read Passport identity in your application
After Passport authenticates a visitor, Vercel stores a signed Passport session token in the _vercel_passport cookie. Vercel also forwards that token to your deployment in the x-vercel-oidc-passport-token request header.
The token is a Vercel-signed Passport identity token (JWT) that includes deployment context and Passport identity claims. Use its sub claim as the stable Passport principal for a visitor. It is scoped to the Vercel team and Connector application. If your application accepts Passport tokens from more than one issuer, use the iss and sub claims together as the visitor identifier. See the Passport token claims reference for the complete token schema.
Profile fields such as email or name are not guaranteed. They only appear if your identity provider returns them in the Passport user info response.
Use @vercel/passport to read the Passport identity from Vercel Functions. The helper reads Vercel's request context by default, verifies the Passport token, and returns identity fields for application code.
Install the package in your project:
pnpm add @vercel/passportThen call getIdentity() from server-side code:
import { getIdentity } from '@vercel/passport';
export async function GET() {
try {
const identity = await getIdentity();
if (!identity) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
return Response.json({
issuer: identity.payload.iss,
subject: identity.subject,
externalSubject: identity.externalSubject,
email: identity.email,
name: identity.name,
});
} catch {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
}Use identity.subject as the visitor identifier for a single Passport issuer. If your application accepts tokens from more than one Passport team, persist identity.payload.iss with identity.subject. Do not parse the subject. identity.externalSubject identifies the visitor in the configured identity provider. A visitor who signs in through a different Connector application or has a different external subject has a different Passport subject. Treat identity.email and identity.name as optional because Passport only includes profile fields returned by your identity provider.
Passport runs in Vercel's network before a request reaches your deployment. A local development server therefore does not receive the real _vercel_passport cookie or x-vercel-oidc-passport-token header.
When neither value is present, getIdentity() returns a Passport-shaped development identity by default and logs a warning the first time it does so. The default identity includes:
subject: owner:local:connector:local:principal:test-user
externalSubject: test-user
email: test-user@passport.local
name: Test UserThe development identity has verified: false and does not contain a token. Use it as a local fixture for application logic, not as proof that the Passport sign-in flow succeeded.
Set development identity fields in your local environment when your application expects particular owner, project, Connector, or visitor values:
VERCEL_PASSPORT_DEV_OWNER=acme
VERCEL_PASSPORT_DEV_OWNER_ID=team_123
VERCEL_PASSPORT_DEV_PROJECT=my-project
VERCEL_PASSPORT_DEV_PROJECT_ID=prj_123
VERCEL_PASSPORT_DEV_CONNECTOR_ID=scl_dev
VERCEL_PASSPORT_DEV_EXTERNAL_SUB=user_dev
VERCEL_PASSPORT_DEV_EXTERNAL_ISS=https://idp.example.comYou can also configure the fixture in code:
const identity = await getIdentity(undefined, {
development: {
owner: 'acme',
ownerId: 'team_123',
project: 'my-project',
projectId: 'prj_123',
connectorId: 'scl_dev',
externalSubject: 'user_dev',
},
});Disable the development identity when you need getIdentity() to return null:
VERCEL_PASSPORT_DEV=0Or disable it for one call:
const identity = await getIdentity(undefined, { development: false });Use a Passport-protected Vercel deployment to test the actual identity provider redirect, session cookie, injected request header, and verified claims. Preview and production deployments do not synthesize a development identity.
Vercel evaluates Passport before deployment routes and Next.js proxy functions run. An unauthenticated browser request is redirected to the identity provider before it reaches your application.
Use the Passport identity in route handlers, server actions, or server components for application-level authorization after Passport has allowed the request. This is useful when your application needs to apply an additional policy, such as allowing only particular Passport subjects to access an admin area.
For policies shared by multiple routes, put the identity check in a shared server-side helper and call it from each protected route.
Do not use a Next.js proxy function to make a Passport-protected path public or to bypass Passport. It runs after Passport has made the sign-in decision. Also, getIdentity() verifies tokens against the Passport JWKS and may make a network request, which is not a good fit for a request proxy. To reach a Passport-protected webhook, cron endpoint, or other machine-to-machine route without a Passport session, the original request must include a Protection Bypass for Automation secret.
Confirm that the request reached a Passport-protected Vercel deployment and that getIdentity() runs in server-side code. A request that uses Protection Bypass for Automation without an existing Passport session does not have a Passport identity and can legitimately return null.
If your server runtime does not expose Vercel's request context, pass its request or headers to getIdentity() explicitly.
Profile and additional claims are optional. Confirm that the identity provider returns the claim and that the Connect application requests and forwards it. Then start a new Passport session. See Configure additional identity scopes.
Treat the request as unauthenticated. Confirm that application code reads the Vercel-injected x-vercel-oidc-passport-token header instead of a client-supplied value. Do not log the raw token while investigating the failure.
Was this helpful?