Configure Workload Identity Federation with deployment pipelines
Keyless authentication from external CI/CD systems to Google Cloud
A practical guide to exchanging deployment-platform OIDC tokens for short-lived Google Cloud credentials with explicit admission and IAM controls.
Workload Identity Federation (WIF) lets a deployment job access Google Cloud without storing a service-account key. The job obtains an OpenID Connect (OIDC) token from its platform. A configured Google provider verifies the token, maps its claims to an identity, and checks conditions restricting which jobs are trusted. Security Token Service (STS) exchanges an accepted token for a short-lived federated token.
Bind the workload that actually deploys
For GitHub, restrict access using immutable repository_id and repository_owner_id claims, plus the required branch, environment, or workflow context. For Vercel, prefer owner_id and project_id over names that can change, and require the intended environment. Vercel does not document an immutability and non-reuse guarantee for those IDs, so high-assurance deployments still need to confirm that assumption. Prefer the team issuer; with the shared global issuer, restrict the team explicitly.
Vercel's documented claims do not distinguish a build from a Function, or one preview branch from another. A production build and production runtime in one Vercel project therefore share the same documented identity boundary. If deployment needs more authority than runtime, use a distinct CI identity such as GitHub Actions OIDC or isolate deployment in another Vercel project; a caller-selectable custom audience is not that separation.
Grant IAM to the exact identity
Bind roles to the narrowest principal. Both forms use the pool project's number, not its ID:
- One mapped subject:
principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT - A deliberately scoped set:
principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.ATTRIBUTE_NAME/ATTRIBUTE_VALUE
Prefer direct resource access where the target API supports federated principals. Where it does not, let the federated identity impersonate a dedicated service account: grant roles/iam.workloadIdentityUser on that account—not merely roles/iam.serviceAccountUser—then grant the account only its workload permissions.
Cloud Run shows why the compatibility matrix matters: its Admin API supports federated API callers, but direct WIF invocation through run.routes.invoke does not. A private service therefore needs a dedicated caller service account with roles/run.invoker on the exact receiving service.
Apply it: Vercel Function to private Cloud Run
Applied example—editorial synthesis: the Vercel Function authorizes the user while Google authenticates the Function's workload identity:
- The browser sends its Better Auth session to a server-side Vercel Function. The Function validates the session and performs application authorization.
- Inside the request handler—not at module initialization—obtain the Vercel OIDC token for the Google provider audience. Google STS exchanges that external subject token for a federated access token.
- Grant the exact federated principal
roles/iam.workloadIdentityUseron the dedicated caller service account. Use IAM CredentialsgenerateIdTokento mint a Google-signed ID token for that account. - Set the Google ID token audience to the generated Cloud Run service URL, or an explicitly configured custom audience. Send it in
Authorization, or useX-Serverless-AuthorizationwhenAuthorizationis deliberately reserved for separate application authorization.
Keep the three audience values distinct:
| Boundary | Audience value |
|---|---|
| Vercel subject JWT | https://iam.googleapis.com/projects/.../providers/... |
| External-account configuration and STS target | //iam.googleapis.com/projects/.../providers/... |
| Google ID token accepted by Cloud Run | Generated service URL or configured custom audience |
Better Auth authenticates the user and manages the application session. Vercel OIDC/WIF authenticates the calling workload. Cloud Run IAM admits that workload. None of those steps automatically authorizes the user's tenant, object, or action. If Cloud Run must make that decision, give it a separately designed and validated user-context contract; never trust browser-supplied identity headers.
Here, “private Cloud Run” means IAM-protected with no anonymous invoker, not necessarily network-private. A Vercel Function can reach ingress all over public HTTPS while IAM still rejects unauthenticated requests. WIF does not create a route to ingress internal; internal-and-cloud-load-balancing requires an external load balancer path.
Pipeline-specific cautions
GitHub Actions. id-token: write only permits the job to retrieve an OIDC token; it grants no cloud write access by itself. Current google-github-actions/auth documentation uses auth@v3 and supports direct federation or impersonation, while Google's deployment guide still embeds older auth@v1 and checkout examples. Recheck action versions, commands, provider claims, and service compatibility when implementing.
Vercel token handling. Builds get one-hour tokens through VERCEL_OIDC_TOKEN. Functions receive request-scoped tokens through x-vercel-oidc-token; Vercel can reuse them for up to 90 minutes and gives them a two-hour lifetime. Development tokens last 12 hours, and local vercel env pull writes one to .env.local. Keep that file untracked, admit development separately, retrieve Function tokens lazily, and do not add an application-level raw-token cache.
Vercel's GCP walkthrough. Its “Service account users role” wording and custom-audience example can mislead implementers. Use Google's roles/iam.workloadIdentityUser for impersonation. Keep the external JWT audience and STS target distinct as shown above; the walkthrough's custom-audience example uses the https://... value for both. Test the exchange with the library versions you deploy.
Sources:
- Google Cloud deployment-pipeline guide(opens in a new tab)
google-github-actions/auth(opens in a new tab)- GitHub Actions OIDC reference(opens in a new tab)
- Vercel OIDC(opens in a new tab), OIDC reference(opens in a new tab), and Vercel's GCP guide(opens in a new tab)
- Security Token Service
token(opens in a new tab) - Federated identity service compatibility(opens in a new tab)
- Cloud Run service-to-service authentication(opens in a new tab)
- Cloud Run ingress(opens in a new tab)