GitHub Actions OIDC to AWS: "Not authorized to perform sts:AssumeRoleWithWebIdentity"
GitHub gave the job a token, and AWS compared it with the role's trust policy. A condition did not match, almost always the one on the sub claim. AWS does not say which condition failed, so the way out is to compare what the token says with what the policy expects.
What it looks like
Assuming role with OIDC Retry AssumeRole: attempt 1 of 12 failed: Could not assume role with OIDC: Not authorized to perform sts:AssumeRoleWithWebIdentity. Retrying after 32ms. ... Error: Could not assume role with OIDC: Not authorized to perform sts:AssumeRoleWithWebIdentity
This is aws-actions/configure-aws-credentials. It retries, and no retry can fix a policy that does not match.
1. A repository created after July 15, 2026: the sub has IDs
From GitHub's changelog of April 23, 2026: "All repositories created after July 15, 2026 will automatically use the new immutable subject claim format," and "Repository renames and transfers after July 15, 2026 will also adopt the new format." The owner ID and the repository ID follow the names:
repo:octo-org/octo-repo:ref:refs/heads/main before repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main immutable
A trust policy written in the old form matches no token from such a repository. October 2026 reports: a repository created on October 8 (gha-runner #89), a deploy through an environment (smart-farm-monitoring #87) and a set of plan and apply roles (Openflows-Infra #54). Read the prefix your repository uses:
gh api repos/OWNER/REPO/actions/oidc/customization/sub
The answer has use_immutable_subject and sub_claim_prefix, such as repo:octo-org@123456/octo-repo@456789. Put that prefix in the policy:
"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"
}
}
- A role that worked can stop after the repository or its owner is renamed or transferred.
- Older repositories keep the old form unless someone turns the new one on in the repository's or organization's OIDC settings.
- If you set it up from the first version of the April post: until June 10, 2026 it showed
-between name and ID. The format uses@. - GitHub Enterprise Server is not part of this change.
2. The part after the repository
- A job with
environment:gets…:environment:NAMEin place of the ref. In smart-farm-monitoring the realsubwas the prefix plus:environment:evaluation. - A
pull_requestrun gets…:pull_request, but only when the job has no environment. - Otherwise it is the ref:
…:ref:refs/heads/main, or…:ref:refs/tags/v1.2.0for a tag. - A colon inside a value becomes
%3A, so an environment namedProduction:V1appears asenvironment:Production%3AV1. - A custom template on the repository or organization (
include_claim_keys) changes the wholesub. With immutable claims, GitHub's documentation says the owner and repository IDs stay in it even then.
3. A wildcard under StringEquals
repo:octo-org@123456/octo-repo@456789:* matches every branch only under StringLike. Under StringEquals the * is a plain character and matches nothing. The configure-aws-credentials README also warns against ForAllValues: in Allow statements, which "return true when the claim is absent or misspelled".
4. The job never asked for a token
Without id-token: write there is no token, and the message is different. The action logs "It looks like you might be trying to authenticate with OIDC. Did you mean to set the id-token permission?" and then fails with "Credentials could not be loaded, please check your action inputs: Could not load credentials from any providers".
permissions: id-token: write contents: read
A permissions: block on the job replaces the workflow's for that job, so it needs id-token: write too. For a reusable workflow from outside your enterprise or organization, the documentation says to set it in the caller.
See what the token says
The README points to github/actions-oidc-debugger, which prints the decoded claims; run it in a private repository only. Compare sub and aud with the trust policy, character for character.
Telling it apart
- "Incorrect token audience": the token's
audis not in the identity provider's client ID list. The action sendssts.amazonaws.comunless theaudienceinput says otherwise. - "No OpenIDConnect provider found in your account for https://
token.actions. githubusercontent.com": the IAM identity provider is missing in the account that owns the role. - From Bitbucket Pipelines, the same AWS message has other causes: Bitbucket Pipelines OIDC to AWS.
See failed jobs from IntelliJ IDEA
Pipeline Inbox for GitHub Actions Workflows, a plugin by Lesstep for JetBrains IDEs 2024.1 or later, lists the runs of all your repositories in an IDE tool window, with their jobs and steps, and your current branch's runs are in the status bar. Reading is free; re-running failed jobs, cancelling, running workflows and reviewing deployments are Pro (US$1.50 a month, with a 30-day trial).
GitHub and GitHub Actions are trademarks of GitHub, Inc.; AWS is a trademark of Amazon.com, Inc. or its affiliates; IntelliJ IDEA is a trademark of JetBrains s.r.o. This page is not affiliated with, sponsored or endorsed by GitHub, Inc., Amazon or JetBrains.
More: "Resource not accessible by integration" · Approving a run that is "Waiting" for review · Bitbucket Pipelines OIDC to AWS · GitHub Actions plugins for IntelliJ IDEA compared · 日本語