CI OIDC tokens are short lived by design. GitLab sets a job token's expiry to the job timeout if one is set, or 5 minutes otherwise. GitHub says the access token the cloud returns is valid only for a single job. That narrow window is the main reason OIDC beats stored keys.
Two different tokens
The word "token" hides two objects, and mixing them up causes confusion.
- The OIDC identity token: a signed JWT from the CI platform that says who the job is.
- The cloud access token: what the cloud provider issues in exchange, if your trust rule accepts the first one.
GitHub's documentation says the cloud provider returns "a short-lived access token that is only valid for a single job, and then automatically expires". Its example token has expiry and issued-at values 300 seconds apart, which suggests a five minute window, but the page does not state that number directly, so treat it as an observation rather than a guarantee.
GitLab is explicit about the identity token: "The expiry time for the token is set to the job's timeout if specified, or 5 minutes if no timeout is specified." GitLab ID tokens are JWTs signed with RS256 using a dedicated private key.
Why lifetime matters
| Credential | Typical lifetime | If stolen from a log or runner |
|---|---|---|
| Stored cloud access key | Until someone rotates it | Works from anywhere until revoked |
| OIDC identity token | Minutes, bound to a job | Narrow window, and audience limits where it works |
| Cloud access token from OIDC | Bounded by the session settings | Expires on its own |
A stored key is a standing credential. A leaked OIDC token is a race the attacker usually loses. They also lose in a second way: the audience. GitLab's guidance says a narrow audience limits which services a stolen token can authenticate with.
What short lifetime does not fix
Short lived does not mean safe. Five minutes is plenty for a script that already runs inside your job. If an attacker can run code in the job, for example through a compromised dependency or action, they can request a fresh token themselves. The protection is the trust rule: what the token is allowed to assume, and under which conditions.
So pair short lifetimes with:
- Tight trust conditions on subject and audience.
- Minimal permissions on the role.
- Pinned third party actions and reviewed workflow changes.
- Session durations set as short as the job allows.
Steps to check your own setup
- Find the longest job in your pipeline. If a deploy runs longer than your session settings, plan for refresh or split the job.
- Check the role session duration in your cloud account and lower it if your jobs are short.
- Set explicit job timeouts. On GitLab, the token expiry follows the job timeout, so a very long timeout means a longer lived token.
- Search logs for decoded tokens. Never print an identity token in a job.
- If a job fails with 401 on GitLab, decode the token in a safe test job to check audience and issuer; GitLab lists mismatched audience values among the common causes.
Quick check
Can I reuse an OIDC token across jobs?
Plan on one token per job. Each job requests its own, and the resulting access token is described by GitHub as valid for a single job.
Is a five minute token safe to print in a log?
No. Treat it as a secret anyway. Logs can be read long after, and replay within the window is still possible.
Safeguard policies and gates can review pull requests that change job timeouts or trust settings, and compliance and evidence automation can record the review. A free scan is at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.