Report #68450
[bug\_fix] invalid\_grant: Token has been expired or revoked \(GCP Workload Identity Federation\)
Ensure the subject token \(OIDC token from external IdP, or AWS signature\) is valid and not expired at the time of exchange. For long-running processes, implement a custom token supplier that fetches a fresh subject token before exchanging it for GCP credentials, or use the provided WIF configuration file \(\`credential\_source\`\) that points to a location/command that always returns a fresh token \(e.g., a file that is updated by a sidecar\). Root cause: Workload Identity Federation exchanges an external security token \(subject token\) for a GCP access token via the GCP STS \`token\` endpoint. The subject token \(e.g., a GitHub OIDC token valid for 5 minutes, or an AWS GetCallerIdentity signature valid for 15 minutes\) must be valid at the time of the exchange. If the GCP access token \(valid for 1 hour\) expires and the client library tries to refresh it, but the original subject token has expired, the refresh fails with \`invalid\_grant\`.
Journey Context:
Developer configures a GitHub Actions workflow to deploy to GCP using Workload Identity Federation \(WIF\) instead of service account keys. They use the \`google-github-actions/auth\` action, which exchanges the GitHub OIDC token for a GCP access token and exports it to \`GOOGLE\_APPLICATION\_CREDENTIALS\`. The workflow has a single long-running job that builds a container for 90 minutes. After exactly 60 minutes \(the GCP access token lifetime\), subsequent \`gcloud\` commands fail with \`ERROR: \(gcloud.builds.submit\) invalid\_grant: Token has been expired or revoked\`. Developer checks the WIF provider configuration \(audience, issuer\) and finds it correct. They examine the \`google-github-actions/auth\` documentation and realize that the exported credential file contains a \`token\` \(the GCP access token\) and a \`refresh\_token\` field, but for WIF, the refresh mechanism requires obtaining a \*new\* GitHub OIDC token \(the subject token\) to exchange again. Since the GitHub OIDC token itself is only valid for 5 minutes, it cannot be used to refresh after 60 minutes. The fix is to re-run the \`google-github-actions/auth\` step before the long-running command, or split the workflow into shorter jobs, or use the \`access\_token\_lifetime\` and \`token\_format\` options to handle the refresh correctly. The journey reveals that WIF does not use traditional OAuth refresh tokens; instead, the client must supply a fresh external subject token for every exchange, which requires architectural changes for long-running processes.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T21:22:39.538473+00:00— report_created — created