"category": "CI/CD federation" · job/github-oidc-immutable-subject
GitHub's immutable OIDC subject claims, fixed in AWS, Azure and Google Cloud
Repositories created after July 15, 2026 send a new sub format with owner and repository IDs. What changed, how to tell which format you get, and the trust changes for each cloud.
- New, renamed and transferred repositories (after July 15, 2026) emit repo:OWNER@OWNER_ID/REPO@REPO_ID:… as the sub claim.
- Existing repositories keep the old name-only format until someone opts them in.
- Trust rules written for the old format stop matching, so deploys fail with an authorization error.
- The durable fix is to trust the numeric IDs, either inside sub or as separate repository_id and repository_owner_id checks.
GitHub Actions jobs get a signed token that cloud providers check before handing out credentials. The most important field in that token is the subject (sub). In 2026 GitHub changed what that field looks like for some repositories, and trust rules written for the old shape stop matching.
What changed in the sub claim?
The old format is built from names only:
repo:octo-org/octo-repo:ref:refs/heads/main
The new immutable format keeps the names and appends the numeric owner and repository IDs after an @:
repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main
GitHub assigns those IDs once and does not reuse them, so a rule that checks them stays tied to the original repository through renames and transfers.[GitHub Docs] The context part after the repository (ref:…, environment:…, pull_request) works as before.
GitHub announced the change on April 23, 2026 and edited the post on June 10, 2026 to switch the separator from a hyphen to @.[GitHub Changelog] Write-ups from before June may show the hyphen form, which GitHub does not issue.
Which repositories send the new format?
From GitHub’s changelog and OIDC reference:[GitHub Changelog][GitHub Docs]
- Repositories created after July 15, 2026 use it by default.
- Repositories renamed or transferred after July 15, 2026 switch to it.
- Older repositories keep the name-only format until an admin opts them in with the toggle in the repository or organization OIDC settings (UI or API).
- GitHub Enterprise Server does not offer it.
So a single organization can have both formats at once. A role that worked for last year’s repository can fail for a repository created last week, even if the trust policy pattern looks like it should cover both.
How do I find the IDs and the format a repository uses?
The IDs come from the REST API. With the GitHub CLI:
gh api repos/OWNER/REPO --jq '{repo_id: .id, owner_id: .owner.id}'
Then decide which format the repository emits: creation, rename or transfer date after July 15, 2026, or the opt-in toggle in its OIDC settings. Microsoft’s migration guide also mentions a GitHub preview endpoint that shows the subject a workflow emits.[Microsoft Learn]
You can paste the owner, repository and IDs into the OIDC trust checker, switch between the two formats and test your existing policy against each.
How do I fix an AWS trust policy?
AWS’s own action README lists this exact case: the trust policy matches the name-only sub, the repository emits the immutable one, and the job fails with “Not authorized to perform sts:AssumeRoleWithWebIdentity”.[AWS (GitHub repository)] There are two ways to fix it.
Option 1 is to match the new sub exactly:
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main"
}
}
Option 2 is to check the ID claims on their own. AWS supports repository_id and repository_owner_id as condition keys and recommends these immutable identifiers because names can change.[AWS IAM User Guide] IAM still requires a sub (or job_workflow_ref) condition on GitHub roles, so keep one for the branch or environment:[AWS IAM User Guide]
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:repository_owner_id": "123456",
"token.actions.githubusercontent.com:repository_id": "456789"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:*:environment:production"
}
}
During a migration you can accept both formats by listing two values for sub under StringEquals. IAM treats multiple values for one key as “any of these”.
How do I fix a Microsoft Entra federated credential?
Entra compares the subject exactly and does not support wildcards in federated identity credentials.[Microsoft Learn] Microsoft’s migration steps avoid downtime:[Microsoft Learn]
- Create a second credential with the immutable subject, keeping the old one.
- Opt the repository in to immutable subjects in GitHub (skip for repositories that already emit it).
- Run the workflow and confirm it signs in.
- Delete the old name-based credential.
{
"name": "octo-repo-main-immutable",
"issuer": "https://token.actions.githubusercontent.com",
"subject": "repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main",
"audiences": ["api://AzureADTokenExchange"]
}
Each app or user-assigned managed identity holds at most 20 credentials,[Microsoft Learn] and you need one per branch, tag or environment. If that limit is close, a flexible credential with a claims-matching expression covers several contexts. For GitHub, Microsoft requires it to match sub plus repository_id, repository_owner_id or both.[Microsoft Learn]
How do I fix Google Cloud workload identity federation?
Google’s guidance for GitHub providers is an attribute condition on the owner, and it recommends the numeric *_id claims over names because names invite squatting.[Google Cloud documentation] A condition like this works with both sub formats, since it never reads sub:
assertion.repository_owner_id == '123456' && assertion.repository_id == '456789'
Check your IAM bindings too. If a binding names a single principal built from the subject (the provider maps google.subject=assertion.sub), its value contains the old sub string. By inference from how that mapping works, it will stop matching once the repository emits the new format. Bindings on a mapped repository_id attribute are not affected.
Migration checklist
- List roles, credentials and providers that trust
https://token.actions.githubusercontent.com. - For each, note the repositories it trusts and whether they emit the new format.
- Add ID-based matching (immutable
sub, orrepository_idandrepository_owner_id). - Opt older repositories in, one at a time, after their trust accepts the new format.
- Remove name-only trust once nothing uses it.
Trust that still depends on names alone carries a second risk beyond broken deploys. See subject recycling.
Questions people ask
- Do my existing repositories switch format automatically?
- No. Repositories that existed before July 15, 2026 keep the name-only format until you opt them in from the repository or organization OIDC settings. A rename or transfer after that date switches the repository to the new format.
- Does this apply to GitHub Enterprise Server?
- No. GitHub's OIDC reference and Microsoft's migration guide both say immutable subjects are not available on GitHub Enterprise Server.
- Can I trust both formats while I migrate?
- Yes. In AWS, list both sub values in the same StringEquals condition (values in a list are OR'ed). In Microsoft Entra, keep the old credential and add a new one. In Google Cloud, conditions on repository_owner_id and repository_id work with either format.
Sources
- Immutable subject claims for GitHub Actions OIDC tokens — GitHub Changelog.# official announcement (issuer) · checked November 10, 2026 (full page text)
- OpenID Connect reference — GitHub Docs.# official documentation (issuer) · checked November 10, 2026 (full page text)
- Configuring OpenID Connect in Amazon Web Services — GitHub Docs.# official documentation (issuer) · checked November 10, 2026 (full page text)
- aws-actions/configure-aws-credentials (README) — AWS (GitHub repository).# official documentation (action maintainer) · checked November 10, 2026 (full README)
- IAM and AWS STS condition context keys — available keys for AWS OIDC federation — AWS IAM User Guide.# official documentation · checked November 10, 2026 (first 100,000 characters of the page (the GitHub and default OIDC sections were inside that range))
- Create a role for OpenID Connect federation (console) — AWS IAM User Guide.# official documentation · checked November 10, 2026 (full page text)
- Migrate GitHub Actions federated credentials to immutable subjects — Microsoft Learn.# official documentation · checked November 10, 2026 (full page text (page dated 2026-07-28))
- Create a trust relationship between an app and an external identity provider — Microsoft Learn.# official documentation · checked November 10, 2026 (full page text)
- Configure Workload Identity Federation with deployment pipelines — Google Cloud documentation.# official documentation · checked November 10, 2026 (full page text)
Update history
- — First published.
Related guides
3 jobs- job/fix-not-authorized-assumerolewithwebidentity category Troubleshooting
Fixing “Not authorized to perform sts:AssumeRoleWithWebIdentity” in GitHub Actions
A checklist for the AWS OIDC error, ordered by how often each cause applies: sub format, job context, wildcards under StringEquals, audience, provider ARN and customized claims.
· 7 min - job/github-oidc-trust-aws category CI/CD federation
One workflow, three clouds: how AWS, Azure and Google Cloud match GitHub OIDC tokens
The same GitHub Actions token is checked three different ways. A side-by-side comparison of where the trust lives, how claims are matched, wildcard support, limits and how failures show up.
· 7 min - job/oidc-subject-recycling category Risks
Subject recycling: when a deleted GitHub name still unlocks your cloud role
Trust rules that match names can be satisfied by whoever registers that name next. What the 2026 research found, what GitHub, GitLab and the clouds changed, and how to audit your own roles.
· 7 min