The id-token: write permission lets a GitHub Actions job request an OpenID Connect (OIDC) token from GitHub. It does not grant write access to your repository, packages, or cloud. Without it, the job cannot fetch the token, so keyless cloud login fails. Grant it only to the jobs that need to authenticate.
Definition
OIDC in Actions means each job can receive a signed JWT that describes the workflow: which repository, which branch or environment, which workflow file. A cloud provider checks that token against a trust rule you wrote and, if it matches, returns a short-lived access token. That replaces a stored cloud key.
The permission name is confusing. GitHub's reference says it only allows the workflow to request and use an OIDC token, and that it does not grant write access to other resources. Think of it as "may ask for a badge", not "may edit things".
What happens without it
If a job lacks the permission, the token cannot be requested. In practice you see a login step fail with an error about a missing token request URL or token. The fix is to add the permission, not to add a secret.
How to set it
Set permissions at the job level so only the job that talks to the cloud gets it:
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cloud login step goes here
run: echo "login with the provider's official action"
The contents: read line matters. Once you write a permissions block, any permission you do not list drops to none. If you use the checkout action, you need contents: read listed explicitly.
What to pair it with
The permission alone is not the security control. The trust rule on the cloud side is. GitHub's guidance is blunt: you must define at least one condition, so untrusted repositories cannot request access tokens for your resources. A trust policy that accepts any token from GitHub's issuer would let any repository on GitHub try to assume your role.
| Piece | Where it lives | What it controls |
|---|---|---|
| id-token: write | Workflow file | Whether the job can fetch a token |
| Audience (aud) | Token and cloud provider | Which service the token is meant for |
| Subject (sub) and other claims | Cloud trust policy | Which repo, branch, or environment is trusted |
Reusable workflows
Reusable workflows owned by the same user, organization, or enterprise expose their OIDC token to the caller's context. For workflows outside your organization or enterprise, GitHub says to set id-token to write explicitly at the caller workflow or job level, so only intended callers receive the token.
Steps to adopt it safely
- Add a permissions block with id-token: write and contents: read to the deploy job only.
- Create the cloud trust rule first, with conditions on audience and subject.
- Replace the stored key with the provider's login action.
- Delete the old secret once a successful run proves the new path works.
- Check that pull request jobs from forks and Dependabot cannot reach the role.
Try it yourself
Click through it at your own pace, or open it full screen. Watch how a pull request is held until checks pass, then think about which of your own workflow jobs should hold cloud access at all.
Quick check
Does id-token: write let a workflow push to my repository?
No. It only allows requesting an OIDC token. Repository write access comes from the contents permission, which you set separately.
Should I set it at the workflow level or the job level?
Prefer the job level, so only the job that needs cloud access can request a token.
Safeguard can enforce policies and gates on pull requests, so a workflow change that widens permissions can be reviewed before merge. You can run a free scan at gold.safeguard.sh/scan.
Sources
- GitHub Docs: OpenID Connect reference
- GitHub Docs: OpenID Connect in Amazon Web Services
- GitHub Docs: OpenID Connect in Microsoft Azure
Last reviewed: 19 October 2026.