A static AWS access key that was deleted from a runbook years ago can still work against production today. OIDC federation removes that problem by ending the practice of storing cloud credentials altogether. Instead of a long-lived key pasted into a build environment, a deployment presents a short-lived token that a cloud provider trusts and exchanges for temporary credentials. The real security boundary is not the token's short life. It is the sub condition that ties access to one project and one environment.
Key takeaways:
OIDC federation on Vercel replaces stored cloud credentials with short-lived, RSA-signed tokens scoped to a single project and environment.
The security gain comes from removing the stored secret, not from the token's short expiry.
A
subcondition pinned to project name and environment is the real access boundary, and a trust policy without it hands the role to any project the issuer recognizes.OIDC federation covers the Vercel-to-cloud direction, so deploying to Vercel from external CI still needs a static
VERCEL_TOKEN.OIDC federation is available on every Vercel plan, so migrating requires no upgrade.
Copy link to headingLong-lived credentials fail by design, short-lived credentials don't
A static access key stays dangerous for every day it remains valid after a leak, and the data shows that window rarely closes. GitGuardian tracked secrets that were confirmed valid in 2022 and retested them in January 2026. Four years later, 64% were still valid and exploitable. Rotation policies had run for four years and were never revoked.
The same pattern holds inside cloud accounts. Datadog found that 59% of AWS IAM users have an active access key older than one year. Those are the keys that get pasted into continuous integration (CI) environment variables and then forgotten.
CI is also where those keys get taken. In January 2023, malware on an engineer's laptop led to a breach at CircleCI and the exfiltration of customer environment variables, tokens, and keys. Two years later, the tj-actions/changed-files supply-chain compromise printed runner secrets straight into build logs. The action was used in more than 23,000 repositories, and CISA added the flaw to its Known Exploited Vulnerabilities catalog, telling affected organizations to treat exposed secrets as compromised.
The through-line is that rotation is a lagging control. It cleans up after exposure instead of preventing it, so a key can sit valid for years before anyone rotates it, and a build log or a stolen laptop session only needs one window. A key that was never stored cannot be pulled from either. OIDC federation puts you in that posture, and being precise about what it does and does not cover is the next step.
Copy link to headingWhat OIDC federation replaces, and what it doesn't
OIDC federation is a trust relationship between an identity provider and the cloud services a deployment needs to reach. When your code calls AWS, it presents a short-lived JSON Web Token (JWT) signed by Vercel's identity provider, and AWS exchanges that token for temporary credentials instead of reading a stored key. The stored secret disappears from your environment variables, which is where the security gain comes from.
This covers the direction that matters most for backend access, which is Vercel reaching your cloud. It does not cover the reverse. Deploying to Vercel from an external CI runner such as GitHub Actions still requires a static VERCEL_TOKEN, and OIDC federation does not change that today. Keep managing that token as the static credential it is.
The AWS path needs a few things in place before you start:
A Vercel project on any plan: OIDC federation is available across every plan, so no upgrade is required.
AWS IAM permissions: You need the ability to create identity providers and roles in the target AWS account.
AWS SDK for JavaScript v3: The
@vercel/oidc-aws-credentials-providerpackage is built for the v3 clients shown below.The Vercel CLI: You use it to pull a development token locally with
vercel env pull.
The GCP and Azure paths follow the same shape with the same claim structure, and this guide treats AWS as the primary route. Before writing any trust policy, it helps to understand how the token is built, because the token's claims are what the policy matches against.
Copy link to headingHow Vercel OIDC tokens work before you configure anything
Every build and every Vercel Function invocation can receive a short-lived JWT signed with RS256. Builds get it as the VERCEL_OIDC_TOKEN environment variable, and Functions receive it on the x-vercel-oidc-token request header. Local development gets the token through vercel env pull, which writes it into .env.local.
The issuer URL depends on which of two modes you select. The table below shows what to match in your cloud trust policy for each:
Vercel recommends Team mode. A team-scoped issuer lets your cloud configuration reject tokens from every other Vercel team at the issuer level, which is the stricter setup.
The sub claim carries the scoping that does the real work. Its format is owner:[TEAM_SLUG]:project:[PROJECT_NAME]:environment:[ENVIRONMENT], so a cloud trust policy can grant production a write role and previews a read-only one. A static access key cannot make that distinction. It carries the same permissions wherever it is copied.
The audience (aud) claim defaults to https://vercel.com/[TEAM_SLUG], and that is the value you pin in the trust policy. The token also carries owner, project, and environment as standalone claims, so a policy can match on one axis without parsing the whole sub string. One claim to avoid in trust conditions is user_id, which appears only in development tokens written by vercel env pull.
Lifetimes vary by context, and Vercel manages them automatically when your code runs on the platform. Build tokens expire after one hour, and Function tokens for preview and production expire after two hours. Rather than mint a fresh token on every invocation, a Function reuses a cached token with enough headroom that it cannot expire inside the function's maximum execution window. Development tokens last 12 hours and refresh when you re-run vercel env pull. The full token anatomy is documented if you want to inspect the claims directly.
Copy link to headingHow to migrate from static keys to OIDC federation in four steps
The migration is four steps on AWS. GCP replaces the identity provider step with a Workload Identity Pool, and Azure with a Federated Credential on a Managed Identity, and both key off the same sub claim.
Copy link to headingStep 1: Enable OIDC federation in project settings
Start in the Vercel dashboard, since the toggle here is what makes the issuer available to your cloud. Open Settings, then Security, and toggle on Secure backend access with OIDC federation. Select Team mode when prompted.
Team mode scopes the issuer URL to your team slug, which lets the issuer and audience conditions in the next steps be as strict as possible. Once the toggle is on, the next step registers Vercel with AWS as a trusted issuer.
Copy link to headingStep 2: Register Vercel as an OIDC provider in AWS IAM
AWS needs to know Vercel as an identity provider before any role can trust it. In the AWS Console, go to IAM, then Identity Providers, select Add Provider, and choose OpenID Connect.
Set the provider URL to https://oidc.vercel.com/[TEAM_SLUG] and the audience to https://vercel.com/[TEAM_SLUG], following the AWS OIDC provider creation documentation. On GCP this step is a Workload Identity Pool and an OIDC provider pointed at the same issuer URL, and on Azure it is a Federated Credential added to a Managed Identity. With the provider registered, you can create a role scoped to your project.
Copy link to headingStep 3: Create a scoped IAM role
Create a role that trusts the new provider, with conditions pinned to your project and the production environment. The trust policy below matches both the sub and the aud on exact strings:
{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::[ACCOUNT_ID]:oidc-provider/oidc.vercel.com/[TEAM_SLUG]" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "oidc.vercel.com/[TEAM_SLUG]:sub": "owner:[TEAM_SLUG]:project:[PROJECT_NAME]:environment:production", "oidc.vercel.com/[TEAM_SLUG]:aud": "https://vercel.com/[TEAM_SLUG]" } } }]}Give previews a separate, lower-privilege role rather than reusing this one. Scope it to read-only access on a dedicated preview bucket or a seeded staging dataset and nothing else, with no write, delete, or key-management permissions, and no reach into production buckets, tables, or queues. Once the role exists, copy its Amazon Resource Name (ARN) into your Vercel environment variables as AWS_ROLE_ARN. The last step swaps the credential provider in your code.
Copy link to headingStep 4: Replace the credential provider in code
Install the provider package alongside the AWS SDK client you use:
pnpm i @aws-sdk/client-s3 @vercel/oidc-aws-credentials-providerThen swap the static credential configuration for the OIDC provider, which exchanges the token for temporary credentials by calling AssumeRoleWithWebIdentity:
import { awsCredentialsProvider } from '@vercel/oidc-aws-credentials-provider';import * as S3 from '@aws-sdk/client-s3';
const s3client = new S3.S3Client({ region: process.env.AWS_REGION!, credentials: awsCredentialsProvider({ roleArn: process.env.AWS_ROLE_ARN!, }),});Deploy, confirm the client works, and then delete AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY from your environment variables. Run vercel env pull so local development writes a fresh VERCEL_OIDC_TOKEN into .env.local. At that point, the static key is gone from every environment, which is the outcome that the whole migration exists to produce.
Copy link to headingThree misconfigurations that quietly undo OIDC federation
The setup above is only as strong as the trust policy behind it, and a few common mistakes give back the security you gained without any obvious error. Each of these fails silently, which is what makes it worth checking before you delete the static key.
Copy link to headingA missing or wildcard sub condition
A trust policy that trusts the issuer but sets no sub condition lets any project that issuer recognizes assume the role. The short token life is no defense here, because an attacker can mint a fresh, valid token from a project they control and the policy accepts it. The short life only limits a stolen token, and this attack never needs to steal one.
The precedent is well documented. The late-2023 response to a GitHub Actions OIDC misconfiguration included blocking new AWS trust policies that lacked a sub condition. Apply the same rule on Vercel and lock the sub to one project and one environment. A StringLike wildcard that matches previews across your whole team fails the same test, since any contributor who can open a branch inherits those credentials.
Copy link to headingThe AWS_REGION multi-region trap
Vercel sets AWS_REGION automatically to the region where the function executes. With multi-region routing, that value can change and point somewhere your S3 bucket or RDS instance does not live, and the call fails or reaches the wrong region. The fix is to declare AWS_REGION explicitly as a Vercel environment variable, set to the region where your resources are. Vercel's AWS documentation calls out this exact pin.
Copy link to headingTeam or project renames that break trust policies
Renaming your Vercel team or project changes the sub, aud, and iss claims, so every trust policy that matches the old values stops working. Under Team issuer mode, a team rename also changes the issuer URL, which means registering a new OIDC provider in AWS and adding a new trust policy statement. Update the cloud side before the rename lands, not after deploys start failing. One related edge lives in code rather than configuration. getVercelOidcToken() from @vercel/oidc cannot run at module level in Function environments, because the token only arrives on the request, so call it inside request handlers.
Copy link to headingHow Vercel secures backend access with OIDC federation
The reason these misconfigurations matter is that the teams running CI-to-cloud pipelines are usually the same ones carrying the most credential risk, and they inherit it from tooling they did not write. Vercel's primitives are built to remove the stored secret and make the boundary explicit, so the failure modes above become configuration you can audit rather than accidents waiting to happen.
Copy link to headingStop storing the cloud key at all
The core pain is that every stored key is a durable liability, valid until someone remembers to rotate it. OIDC federation removes the key from the environment entirely and replaces it with a token minted per build or per invocation, signed by Vercel and exchanged by your cloud provider. There is nothing left in your environment variables for a build log or a stolen session to leak.
Copy link to headingMake the access boundary the sub claim
Security teams need access that differs by environment, and a static key cannot express that. Because the sub claim encodes team, project, and environment, a trust policy can grant production one role and previews another, so a preview deployment never inherits production access. That granularity is what makes secretless backend access structurally different from rotating a static key on a schedule.
Copy link to headingReach private backends without opening them up
Many backends are not on the public internet, and teams often solve that by punching holes or copying more credentials around. Secure Compute opens private connections from Vercel Functions with dedicated static IP addresses and VPC peering into internal APIs, databases, and Kubernetes clusters, so a Function can reach a private resource over OIDC-issued credentials without exposing it publicly.
Copy link to headingVerify the change on a preview before you commit
The riskiest moment in any credential migration is deleting the old key before the new path is proven. Every pull request on Vercel gets a production-grade preview deployment, so you can confirm the Function assumes the role and reaches your backend on a real URL before you remove AWS_ACCESS_KEY_ID anywhere.
Copy link to headingShip secretless backend access on Vercel
The static key you never store cannot be pulled from a build log, a runner's memory, or a stolen laptop session, and the data shows that stored keys stay valid and exploitable for years after they leak. Moving CI-to-cloud access onto OIDC federation ends that exposure at the source, and pinning the sub claim to one project and environment turns access into something you can reason about instead of a credential copied wherever it is convenient.
Here is what Vercel gives you to make that migration real:
OIDC Federation: Short-lived, RSA-signed tokens that replace stored AWS, GCP, and Azure credentials, available on every plan.
sub-scoped access: Trust policies that grant production and preview environments different roles from the same identity, with no shared static key.Secure Compute: Private VPC peering and dedicated static IP addresses so Functions reach internal APIs, databases, and Kubernetes clusters without public exposure.
Environment variables: Encrypted storage for the values you still keep, such as the
AWS_ROLE_ARNand an explicitAWS_REGION.Preview deployments: A production-grade URL on every pull request to verify the assumed role before you delete any static key.
Start a new project and wire up OIDC federation on your first deploy, or browse templates to begin from a foundation you can grow into.
Copy link to headingFAQs about OIDC federation
Copy link to headingDoes Vercel OIDC federation work for deploying to Vercel from GitHub Actions?
No. OIDC federation covers builds and Functions authenticating outward to services like AWS, GCP, and Azure. Deployments from GitHub Actions to Vercel still require a static VERCEL_TOKEN, which you manage as a standard CI secret.
Copy link to headingWhich Vercel plans support OIDC federation?
All of them. Secure backend access with OIDC federation is available on every Vercel plan, so no upgrade is required to migrate a project off static cloud keys.
Copy link to headingHow long do Vercel OIDC tokens last?
Build tokens expire after one hour, and Function tokens for preview and production expire after two hours. Development tokens last 12 hours and refresh when you re-run vercel env pull. Vercel manages expiry automatically when your code runs on the platform.
Copy link to headingDoes OIDC federation work with GCP and Azure, or only AWS?
AWS, GCP, and Azure all have documented federation paths that key off the same sub claim. AWS uses awsCredentialsProvider(), while GCP and Azure consume the token through getVercelOidcToken(). Any provider that accepts an OIDC JWT can use the same token.
Copy link to headingCan I use OIDC for Turborepo Remote Caching in external CI?
Yes, through a separate flow. External CI pipelines exchange their own OIDC tokens for short-lived Turborepo access tokens that grant access only to the Remote Cache and belong to the team rather than an individual member.