Issuers
Trust tokens from Vercel, GitHub Actions, Google Cloud, AWS, GitLab and any other OIDC issuer.
Each entry in Issuers is one source of tokens. A token is accepted when its issuer, audience and claims match an entry. Every entry accepts these settings:
| Setting | What it does |
|---|---|
Name |
A name for log messages and for [RequireOidcToken(...)]. Defaults to the preset name or the issuer URL. |
Preset |
Vercel, GitHubActions, or Custom (the default). |
Audience |
The aud the token must carry, which names the service the token was made for. |
RequiredClaims |
Claims the token must carry, each with its allowed values. Added to the preset’s own rules. |
AllowPreview |
Whether the token also unlocks draft content, as the API key does. Defaults to true. |
MetadataAddress |
Where the issuer publishes its keys. Defaults to {issuer}/.well-known/openid-configuration. |
Vercel
See Vercel’s OIDC federation docs for how tokens are issued and what they contain.
{ "Preset": "Vercel", "Team": "acme" }
Teamis your team slug, and the only required setting. Tokens from any other team are refused.Projectslimits access to some of the team’s projects, by name or id, such as["acme-web", "prj_123"]. Leave it out to accept every project in the team.Environmentsdefaults toproductionandpreview. To let local machines in as well, adddevelopment:"Environments": ["production", "preview", "development"]. Thedevelopmenttoken is the onevercel env pullwrites for local work, and anyone on the team can pull it.IssuerModeisTeam(the default) orGlobal, matching your team’s OIDC settings on Vercel.Audiencedefaults tohttps://vercel.com/{team}, which is whatgetVercelOidcToken()returns.- Builds get a token too, through
VERCEL_OIDC_TOKEN, so static generation works.
GitHub Actions
See GitHub’s OpenID Connect docs for how workflows request tokens and what they contain.
{ "Preset": "GitHubActions", "Owner": "acme" }
Owner is your GitHub organization, or a user, written as GitHub writes it. It is the only required setting, and tokens from any other owner are refused. On its own it accepts every repository the owner has. To narrow it down, add any of these filters:
Repositories, asowner/repo, such as["acme/site"].Refs, such as["refs/heads/main"].Environments, the GitHub deployment environments allowed in.
Request the token in a job with permissions: id-token: write:
const token = await core.getIDToken();
The token’s audience says which service it was made for. Without an argument, GitHub uses https://github.com/{owner}, which is also this preset’s default. With that default, a token your workflows send to another service that accepts GitHub’s default audience would also work on your CMS. To keep them apart, pick your own audience: set it as Audience, such as "https://cms.example.com", and pass the same value to core.getIDToken('https://cms.example.com').
Any other issuer
Issuer, Audience and at least one required claim are needed. Without a claim, any workload the issuer serves could get in. With Google, for example, that would be anyone with a Google account. Each required claim must match a top-level string claim in the token, including its case.
Google Cloud
Request an ID token from the metadata server with your audience, and require the service account’s email:
{
"Name": "renderer",
"Issuer": "https://accounts.google.com",
"Audience": "https://cms.example.com",
"RequiredClaims": { "email": ["renderer@acme.iam.gserviceaccount.com"] }
}
AWS
Request a token with GetWebIdentityToken after enabling outbound identity federation on the account. The issuer is specific to your account, and sub is the ARN of the role that asked for the token:
{
"Name": "lambda-renderer",
"Issuer": "https://abc123-def456-ghi789-jkl012.tokens.sts.global.api.aws",
"Audience": "https://cms.example.com",
"RequiredClaims": { "sub": ["arn:aws:iam::123456789012:role/Renderer"] }
}
GitLab CI
Declare an ID token in the job with your audience, and require the project path:
{
"Name": "gitlab-build",
"Issuer": "https://gitlab.com",
"Audience": "https://cms.example.com",
"RequiredClaims": { "project_path": ["acme/site"] }
}