DEV Community

Jason Paul for AWS Community Builders

Posted on • Originally published at linuxtek.ca

GitHub Actions OIDC Changes

Introduction

If you're familiar with using OpenID Connect (OIDC) to authenticate GitHub Actions to your cloud provider (AWS, GCP, etc), you'll know that this is a more secure way to build cloud infrastructure than storing static credentials. What you may not know is that any new repository created after July 15, 2026 is going to have a slightly different configuration needed. And your favourite AI agent may not know about it yet either.

This article will go over the change where new repositories will use an immutable subject format, to ensure the subject claim is unique. This requires you to add additional information to the repository format in your policy configuration.

Special thanks to Gagandeep Kaur for the troubleshooting session where we figured this all out!

Background

This is the basic workflow when using OIDC with GitHub Actions and any cloud provider:

If you're not familiar with OIDC, I'll direct you to this repo from Edwin Moedano Cardiel, who presented a Dev Chat on this topic at AWS Summit Toronto 2026. The repo includes a number of guardrails when automating infrastructure deployments with Terraform via GitHub Actions. Here is my article, which has a number of photos and details of the presentation. In this article, I will give examples using AWS, however the same issue will apply when using OIDC with other cloud providers.

The Update

From the GitHub Documentation on Immutable Subject Claims:

The OpenID Connect (OIDC) specification requires subject (sub) claims to be locally unique and never reassigned. Previously, the default sub format used only organization and repository names. If a namespace was recycled, a different owner could create the same subject value.

To help prevent this scenario, repositories created after July 15, 2026 now use an immutable default subject format that includes both the owner ID and repository ID. This rollout does not include GitHub Enterprise Server.

  • Syntax: repo:OWNER@OWNER-ID/REPO@REPO-ID:ref:refs/heads/BRANCH
  • Previous format example: repo:octo-org/octo-repo:ref:refs/heads/main
  • Immutable format example: repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main

The @ separator is used between names and IDs because @ cannot appear in GitHub usernames or repository names.

Repositories created before July 15, 2026 keep the previous format unless you opt in to immutable subject claims. You can opt in at the organization or repository level by using the OIDC settings UI or REST API.

Repository renames and transfers after July 15, 2026 also move to the immutable subject format.

So what does this mean?

For any GitHub repository created after July 15, 2026, or that have opted in to immutable subject claims, the trust policy used with the cloud provider must be updated to append the permanent numeric ID for the organization name and repository name. This is to ensure a recycled org or repository name cannot be used to mint tokens matching a stale trust policy.

Configuration Example

For details on how to configure OIDC with other cloud platforms, see this page: Security Hardening Your Deployments.

As an example, with AWS, this is what the trust policy format added to IAM would need to be updated to:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::<YOUR_AWS_ACCOUNT_ID>:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
                    "token.actions.githubusercontent.com:sub":"repo:<YOUR_ORG_NAME>@<YOUR_ORG_ID_NUMBER>/<YOUR_REPO_NAME>@<YOUR_REPO_ID_NUMBER>:ref:refs/heads/*"
                }
            }
        }
    ]
}

Organization ID Number

To get the organization ID number, access the GitHub API via URL: https://api.github.com/orgs/ORG_NAME.

This can be done via curl, or in a web browser. The ID value in the response is the first number you'll need.
Alternatively, you can use the GitHub CLI and run gh api users/org_name --jq '.id'.

Repository ID Number

To get the repository ID number, access the GitHub API via URL: https://api.github.com/repos/OWNER/REPO.

This can be done via curl or in a web browser. The ID value in the response is the first number you'll need.

Alternatively, you can use the GitHub CLI and run gh api repos/org_name/repo_name --jq '.id'

Plugging It In

Once you have the values, the string would be formatted like:
"token.actions.githubusercontent.com:sub": "repo:octo-org@123456/octo-repo@456789:ref:refs/heads/demo-branch"

Troubleshooting

Setting Confirmation

Confirm if the repository and organization have opted in to the "Use immutable subject claim" setting. While accessing a repository, go to Settings > Actions > OIDC. You'll see the "Use immutable subject claim" option set. If it is greyed out such as in this case, the repository has been opted in by policy, or was created after the July 15, 2026 date.

In the case of an Enterprise repository, you may not have access to see this setting, so contact your GitHub Administrators to confirm.

Terraform Errors

When using GitHub Actions aws-actions/configure-aws-credentials@v4 to configure credentials for Terraform to use for AWS, be sure to pay attention to the audience and subject, limit the scope of the role to least privilege. You can also adjust the trust subject to a specific branch of your repository.

Without the proper subject based on this setting change, the trust relationship will fail, and you will run into errors when the GitHub Actions runner attempts to assume the role to execute the Terraform plan or apply, such as:

Could not assume role with OIDC: Not authorized to perform sts:AssumeRoleWithWebIdentity

Conclusion

You may not run into this issue for existing repositories, or in certain enterprise organizations, however it is important to be aware that this change will apply to any new repositories in the future. Make sure to understand the difference between the subject claims:

# Legacy (mutable) sub claim
repo:octo-org/octo-repo:ref:refs/heads/main

# Immutable sub claim
repo:octo-org@123456/octo-repo@789012:ref:refs/heads/main

Resources

Top comments (0)