Join our Newsletter — 33% off our NHI Course
Home› Guides› GitHub Actions OIDC Errors Troubleshooting Guide
Guide Cloud & Workload Identity

GitHub Actions OIDC Errors Troubleshooting Guide

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 11 November 2026 15 min read
On this page

When a GitHub Actions job fails to get cloud credentials through OpenID Connect, the error usually names the cloud, but the fault is just as often in the workflow file, the repository settings or the shape of the subject claim. This guide works through GitHub Actions OIDC failures from the GitHub side: the job cannot request a token at all, the cloud rejects the token, or the exchange succeeds and the next API call is denied. Each section gives the symptom, the likely causes from most to least common, where to look, the fix, and how to stop it coming back. Error strings are quoted from GitHub, AWS, Microsoft and Google documentation and the official login actions, checked on 11 November 2026. It is for platform, DevOps and cloud security engineers; generic federation faults on Kubernetes and between clouds are covered in the Multi-Cloud Workload Identity Troubleshooting Guide, which this page does not repeat.

Key takeaways

  • Read the subject claim before touching the trust. The job's actual sub value, compared character for character with the cloud's trust condition, explains most rejections in all three clouds.
  • No id-token: write, no token. Setting any permission in a permissions: block sets the rest to none, so adding contents: read alone silently removes OIDC.
  • Environments change the subject. A job that references an environment gets repo:ORG/REPO:environment:NAME, not the branch form, so adding an environment to a working job breaks a branch-based trust.
  • The subject format is moving. Repositories created, renamed or transferred after 15 July 2026 emit an immutable subject that includes owner and repository IDs; trust conditions written for the name-only form stop matching.
  • Never fix a mismatch with a wildcard. Widening the trust to a whole organisation or every ref lets any workflow in scope mint cloud credentials, which is exactly what attackers who inject workflows look for.

Where a GitHub Actions OIDC exchange fails

Every run follows the same sequence. The job asks the GitHub OIDC provider for a JSON Web Token (JWT) signed by https://token.actions.githubusercontent.com, a login action presents it to the cloud's token service, the cloud checks the issuer, audience and subject against a trust configuration, and returns short-lived credentials. The credentials are then used against cloud APIs, where ordinary authorisation applies. Locate the failing stage first.

StageTypical symptom in the job logWhere the fault usually is
1. Token requestUnable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable or the matching ..._TOKEN messageWorkflow permissions:, fork or Dependabot trigger, reusable workflow caller
2. Issuer and audienceIssuer "does not match the expected ones" (Google Cloud), invalid token, audience rejectedEnterprise issuer URL, audience input on the login action, provider registration in the cloud
3. Subject and claim matchNot authorized to perform sts:AssumeRoleWithWebIdentity, AADSTS700213, Failed to generate Google Cloud federated tokenTrust policy condition, federated credential subject, attribute condition
4. Credential issueFailed to generate OAuth 2.0 Access Token (Google Cloud), no subscription selected (Azure)Impersonation binding, subscription or tenant input
5. API authorisationAccessDenied, AuthorizationFailed, PERMISSION_DENIED on a later stepRole grants, not OIDC. See the cloud-specific guides linked below

Symptom 1: the job cannot get an OIDC token

The @actions/core toolkit throws Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable or Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable when the runner was not given the request URL and bearer token. The login actions surface this as a failure to fetch the ID token. Other toolkit errors at this stage are Failed to get ID Token followed by an HTTP status, and Response json body do not have ID Token field.

Likely causes, most common first

  1. Missing permission: the job or workflow does not grant id-token: write. GitHub's workflow syntax lists the values as write or none and states that if you specify access for any permission, all unspecified ones are set to none. A hardening change that adds permissions: contents: read at the top of the file is the classic trigger.
  2. Fork pull requests: for pull_request events from a fork, unless the repository setting to send write tokens to fork workflows is enabled, GitHub changes write permissions to read, so id-token: write is not honoured. This is the intended behaviour, not a bug.
  3. Dependabot runs: Dependabot-triggered runs are treated like fork runs, with a read-only token and no secrets.
  4. Reusable workflows: a called workflow cannot hold more permission than the caller grants, so the caller job must grant id-token: write as well.

Diagnose and fix

  • Where to look: the "Set up job" section of the log lists the effective GITHUB_TOKEN permissions. If IdToken is not write, the fix is in YAML.
  • Fix: grant id-token: write at job level on the deploy job only, alongside the minimum other permissions it needs. Do not grant it at workflow level for jobs that build or test untrusted code.
  • Fork contributions: do not enable write tokens for fork workflows to make OIDC work. Run cloud deployments on push to a protected branch or behind an environment with required reviewers instead.
  • Prevent: lint workflows for deploy jobs that use a cloud login action without id-token: write, and for id-token: write granted at workflow level.

Symptom 2: the cloud rejects the subject

This is the most common class. The token is valid, but its sub (or another claim used in a condition) does not equal what the trust expects. GitHub's OIDC reference defines these default subject formats:

Job contextDefault sub valueNotes
Job references an environmentrepo:ORG-NAME/REPO-NAME:environment:ENVIRONMENT-NAMETakes precedence over branch and pull request forms
Pull request event, no environmentrepo:ORG-NAME/REPO-NAME:pull_requestNo branch name in the subject
Branch, no environmentrepo:ORG-NAME/REPO-NAME:ref:refs/heads/BRANCH-NAMEA renamed default branch changes it
Tag, no environmentrepo:ORG-NAME/REPO-NAME:ref:refs/tags/TAG-NAMERelease workflows triggered by tags
Immutable format (repositories created, renamed or transferred after 15 July 2026)e.g. repo:octo-org@123456/octo-repo@456789:ref:refs/heads/mainIncludes owner and repository IDs; not on GitHub Enterprise Server
Custom subject templateWhatever include_claim_keys definesReplaces the whole default format

Any : inside a metadata value is encoded as %3A. For reusable workflows, the job_workflow_ref claim carries the called workflow path, for example octo-org/octo-automation/.github/workflows/oidc.yml@refs/heads/main, and a custom template can include it in the subject.

Likely causes, most common first

  1. An environment was added to the job: the subject switched from ref: to environment:.
  2. Wrong event: the trust allows ref:refs/heads/main but the run was a pull request, which emits pull_request.
  3. Immutable subject: a new, renamed or transferred repository now emits the ID form. The aws-actions/configure-aws-credentials documentation names Not authorized to perform sts:AssumeRoleWithWebIdentity as the result when a trust policy uses the legacy name-only form and the repository emits the immutable claim.
  4. Custom template drift: an organisation or repository subject template was changed with PUT /repos/{owner}/{repo}/actions/oidc/customization/sub (or the organisation equivalent) before the cloud trust was updated. GitHub advises creating the matching cloud condition first.
  5. Case or typo: Entra ID matches subjects exactly; AADSTS7002138 says the subject matches case-insensitively but not case-sensitively.

Diagnose and fix

  • Read the subject: the Azure/login action prints the subject claim in its log; for other clouds, decode the token payload locally in a non-production run (never in an online decoder) and read sub, aud, iss, environment, ref, event_name and job_workflow_ref.
  • Fix the side that is wrong: if the workflow changed legitimately (new environment, immutable IDs), add an exact trust entry for the new subject. If the run should not have deployment rights (a pull request), the rejection is correct.
  • Prefer environments for multiple branches: Microsoft notes that pattern matching is not supported for branches and tags in federated identity credentials and suggests an environment instead, which also lets you require reviewers.
  • Prevent: manage trust conditions in infrastructure as code beside the workflow, and test subject changes in a non-production role first.

Cloud-specific error reference

CloudExact error textMeaning and fix
AWSNot authorized to perform sts:AssumeRoleWithWebIdentityRole trust does not accept the token: check the token.actions.githubusercontent.com:sub and :aud conditions, the OIDC provider ARN in the principal, and the immutable subject form
AWSCredentials loaded by the SDK do not matchThe action's credential check failed after loading; the action documentation suggests the role-chaining input when chaining from existing credentials
AWSAudience rejectedThe action defaults audience to sts.amazonaws.com; the IAM OIDC provider must list the same client ID. Non-default partitions need the audience input
Microsoft EntraAADSTS700213: No matching federated identity record found for presented assertion subjectNo federated credential subject equals the token subject; copy the subject from the run log exactly
Microsoft EntraAADSTS7002138Case differs between credential and token, or the credential includes numeric owner and repository IDs that the token does not contain
Google CloudFailed to generate Google Cloud federated tokenThe token was not admitted to the workload identity pool: check the attribute condition
Google CloudFailed to generate OAuth 2.0 Access TokenService account impersonation failed: check the roles/iam.workloadIdentityUser binding and its principalSet
Google CloudThe size of mapped attribute exceeds the 127 bytes limit.A long repository or branch name in a mapped claim; shorten names or map a shorter claim
Google CloudThe access token lifetime cannot exceed 3600 seconds.Runner clock skew; fix NTP on self-hosted runners or set access_token_lifetime to about 3300s
Google CloudIssuer "does not match the expected ones"Provider issuer differs from the token iss; GitHub Enterprise Cloud or Server may use a different issuer URL from the public one

Two configuration details trip teams up repeatedly. On AWS, configure-aws-credentials now ignores any thumbprint you specify, so editing thumbprints does not fix a trust error. On Azure, Azure/login requires subscription-id unless allow-no-subscriptions is true, and its default audience is api://AzureADTokenExchange, which must match the federated credential. Step-by-step setup is in How to set up workload identity federation for GitHub Actions to AWS and How to Federate github actions to google cloud.

Symptom 3: login succeeds, the next step is denied

If the login action reports success and a later CLI or SDK call fails with AccessDenied, AuthorizationFailed or PERMISSION_DENIED, OIDC is working and the problem is authorisation on the role, service principal or service account. Do not edit the trust. Use the cloud's own tooling: IAM policy simulation on AWS, the activity log and role assignments on Azure (see the Azure AuthorizationFailed Troubleshooting Guide), and Policy Troubleshooter on Google Cloud (see the Google Cloud PERMISSION_DENIED Troubleshooting Guide). Allow for propagation after a new grant before you redesign anything.

A safe diagnostic procedure

  1. Classify the stage from the table above using the first error line, not the last.
  2. Check permissions in the "Set up job" log and the trigger event. Stop here if IdToken is not write.
  3. Capture claims safely in a throwaway branch or non-production role: decode locally, record iss, aud, sub, environment, job_workflow_ref, then let the token expire.
  4. Diff the trust: compare those values with the AWS role trust policy, the Entra federated credential, or the Google Cloud attribute mapping and condition. Look for environment, event, case and ID-format differences.
  5. Change one thing, in code, with a pull request reviewed by the cloud owner. Add an exact entry rather than widening an existing one.
  6. Retest and roll back cleanly: re-run the job; if it still fails, revert the trust change rather than stacking a second change on top.
  7. Record the cause so the same subject change is caught by linting next time.

Decision guidance: fix, widen or redesign

SituationPreferred fixAvoid
Several branches deploy to the same accountOne environment with protection rules, trust on the environment subjectWildcard on ref:*
Central deployment logic in a reusable workflowCustom subject template including job_workflow_ref, trust pinned to that workflow path and refTrusting every repository in the organisation
Many repositories, one platform teamPer-repository roles or credentials generated from a templateOne shared role with an organisation-wide subject
Repository renamed or transferredUpdate to the immutable ID subject, which survives future renamesKeeping both old and new names indefinitely
Pull requests need cloud read access for plansSeparate read-only role trusted for pull_requestReusing the deploy role

Small organisations with a handful of repositories can manage exact subjects by hand in each cloud. Larger estates should generate trust entries from a repository inventory and enforce an organisation subject template, because per-cloud limits apply: Entra allows a maximum of 20 federated identity credentials per application or user-assigned managed identity, so a design that adds one credential per branch will hit the ceiling.

Where identity fits

Each trust entry is a non-human identity binding: a role, service principal or service account that any matching workflow can become. The subject condition is the only thing standing between a repository's code and the cloud permissions, so treat trust changes as privileged access changes with owner review. The GitHub Actions OIDC Federation Hardening Guide covers the design side, and the How to Audit entra workload identity federated credentials page covers review.

Detection and measurement

  • AWS: CloudTrail AssumeRoleWithWebIdentity events record the role and session name; set role-session-name to include ${{ github.run_id }} so each AWS action traces back to a run. Alert on UpdateAssumeRolePolicy for CI roles.
  • Microsoft Entra: service principal sign-in logs show failed exchanges with their AADSTS codes; audit logs show federated credential changes.
  • Google Cloud: Security Token Service and IAM audit logs show exchanges and setIamPolicy changes to workloadIdentityUser bindings. See the Google Cloud Audit Logs and Log Sinks Guide.
  • GitHub: organisation audit log entries for subject template changes and Actions permission settings.

Metrics that show the estate is healthy:

  • OIDC exchange failure rate per repository, grouped by error code.
  • Number of trust entries using wildcards or organisation-wide subjects (target zero, or documented exceptions with expiry).
  • Repositories still holding long-lived cloud keys as secrets alongside an OIDC path.
  • Median time to resolve an OIDC failure.
  • Share of trust changes made through reviewed infrastructure as code.

Common failure patterns

  • Widening to end an outage: changing repo:org/app:ref:refs/heads/main to repo:org/* restores deployments and lets every repository in the organisation assume the role.
  • Putting a key back "temporarily": a stored cloud key added to unblock a release becomes the long-lived secret OIDC was meant to remove. In the tj-actions/changed-files compromise, a poisoned action dumped CI secrets from runner memory into workflow logs.
  • Granting id-token: write everywhere: setting it at workflow level gives build and test jobs that run third-party code the ability to request tokens. In the Megalodon GitHub Actions attack, injected workflows harvested CI secrets and OIDC tokens; tight subject conditions and job-level permissions limit what a stolen token can do.
  • Enabling write tokens for forks: done to make pull request previews deploy, it hands cloud access to external contributors' code.
  • Changing the subject template first: switching an organisation template before every cloud trust is updated breaks every repository at once.
  • Debugging thumbprints: time spent on thumbprints that the AWS action now ignores, while the real fault is a subject mismatch.

Framework mapping

FrameworkReferenceRelevance
NIST SP 800-53 Rev. 5IA-9 Service Identification and AuthenticationPipelines authenticate to clouds with federated identity instead of shared secrets
NIST SP 800-53 Rev. 5IA-5 Authenticator ManagementRemoving long-lived keys that OIDC replaces
NIST SP 800-53 Rev. 5AC-6 Least Privilege; CM-3 Configuration Change ControlExact subject conditions; reviewed trust changes
NIST CSF 2.0PR.AA-01, PR.AA-05Managing service identities and enforcing access policy
CIS Controls v8.16.8 Define and Maintain Role-Based Access ControlPer-repository roles rather than shared deploy roles
MITRE ATT&CKT1528 Steal Application Access Token; T1550.001 Application Access Token; T1078.004 Cloud AccountsWhat a compromised workflow does with tokens it can request

Practitioner checklist

  • Grant id-token: write only on deploy jobs, at job level, and confirm it in the "Set up job" log.
  • Read the actual sub from a run before editing any trust condition.
  • Check whether the job uses an environment, a pull request trigger or a reusable workflow, as each changes the claims.
  • Plan for the immutable owner and repository ID subject on new, renamed and transferred repositories.
  • Update cloud trusts before changing an organisation or repository subject template.
  • Keep trust entries exact; record any temporary widening as an exception with an expiry.
  • Never re-add a stored cloud key to unblock a deployment.
  • Put the run ID in session names and alert on trust policy and federated credential changes.
  • Track exchange failures by error code and remove stale trust entries quarterly.

Standards and references

Related NHI Mgmt Group resources: GitHub Actions OIDC Federation Hardening Guide · Multi-Cloud Workload Identity Troubleshooting Guide · GitHub and GitHub Actions Security Guide · Workload Identity Federation Trust Review Checklist

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 11 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org