Yes. A GitLab CI job can request an ID token, a signed JSON web token, and present it to a cloud provider that trusts GitLab as an identity provider. The provider checks claims such as project and branch, then issues short-lived credentials. No long-lived access key has to sit in a CI/CD variable.
What an ID token is
GitLab describes ID tokens as JSON web tokens generated by GitLab CI/CD, used to authenticate with third-party services such as secrets providers and cloud platforms. You declare one under the id_tokens keyword in a job. The token is signed with RS256, and it expires when the job's timeout is reached, or after 5 minutes if no timeout is set.
deploy:
id_tokens:
CLOUD_TOKEN:
aud: https://cloud.example.internal
script:
- ./exchange-token-for-credentials.sh "$CLOUD_TOKEN"
The script name is a placeholder for whatever your provider's login step is.
The claims that matter
| Claim | What it tells the provider | Trust level |
|---|---|---|
project_id, namespace_id | Which project and group ran the job | Stable, preferred |
ref_protected | Whether the Git ref is protected | Useful for production roles |
environment | Deployment target, present only if the job names one | Useful |
ref | The branch or tag | Fine with other claims |
user_login, user_email | The person who triggered it | Do not rely on alone |
GitLab's own guidance is to use project_id and namespace_id in trust policies because renames do not change them, and not to rely on user_login or user_email as the sole condition because a user can change them.
Steps to adopt it
- Register GitLab as an OpenID Connect identity provider in your cloud account.
- Create a role that trusts that provider, and write the trust policy on
project_idornamespace_id, plusref_protectedfor production. - Give each service its own
audvalue. The docs note that a different audience per service limits how far a stolen token travels. - Add the
id_tokensblock to the deploy job only, not the whole pipeline. - Delete the old stored key from CI/CD variables, then rotate it at the cloud side.
Gotchas
The older CI_JOB_JWT_V2 variable is deprecated and can cause 401 errors, so move to id_tokens. GitLab also blocks issuing a token when a sub path was previously used by a different project, so an old trust policy cannot be inherited by a renamed or recreated project. Extra claims as cloud condition keys are described as available on GitLab.com, while self-managed instances may be limited to sub, so check your own setup before relying on them.
A token is still a credential for its short life. Anyone who can change the job script can print it. Pair this with protected branches and protected environments so that only reviewed code runs in the job that asks for one. The same pattern on another platform is covered in GitHub Actions OIDC instead of long-lived cloud secrets.
Safeguard's policies, gates and guardrails can add automated checks to changes that touch pipeline configuration. You can try a free scan at https://gold.safeguard.sh/scan.
Quick check
Is an ID token safer than a stored key?
Usually, because it expires in minutes and is bound to a project and ref. It does not remove the need to control who can edit the job.
Which claim should a production role check?
Check a stable project identifier and ref_protected, so only jobs on protected refs can assume it.
Sources
- GitLab Docs: OpenID Connect ID tokens and the id_tokens keyword, fetched 19 October 2026.
Last reviewed: 19 October 2026.