The GitHub OIDC sub claim changes with the job. A job that uses an environment gets repo, then the environment name. Without an environment, a branch job gets the ref, a tag job gets the tag ref, and a pull request job gets the string pull_request. Your cloud trust rule must match the format you intend.
The default formats
GitHub's reference lists these defaults, where ORG-NAME and REPO-NAME are your owner and repository:
| Job type | Default sub format |
|---|---|
| Uses an environment | repo:ORG-NAME/REPO-NAME:environment:ENVIRONMENT-NAME |
| Pull request, no environment | repo:ORG-NAME/REPO-NAME:pull_request |
| Branch, no environment | repo:ORG-NAME/REPO-NAME:ref:refs/heads/BRANCH-NAME |
| Tag, no environment | repo:ORG-NAME/REPO-NAME:ref:refs/tags/TAG-NAME |
Two details trip people up. First, an environment takes priority: if the job names an environment, the sub uses the environment form even on a branch. Second, colons in metadata are encoded as %3A, so an environment called Production:V1 appears as Production%3AV1.
Which one to trust
The most predictable choice for deploys is the environment form. You pair it with an environment that has protection rules, so the token is only issued to jobs that already passed those rules in the sense that the environment is attached to the job. That lets the cloud role say "only the prod environment of this one repository".
Branch based trust works too, but be explicit. A rule matching a single ref, such as the main branch, is far tighter than a wildcard over the whole repository.
Pull request jobs deserve their own thought
Pull request jobs get the pull_request form. If your trust rule accepts that form, any pull request that can run a workflow with the token permission may request cloud credentials. Usually you want pull request jobs to have no cloud role, or a read only one in a sandbox account. Keep the deploy role limited to environment or main branch subjects.
Customizing the claim
You can change the format. Customization replaces the entire sub claim with a new one built from the claim keys you list, set through a REST API request. A repository level template is set with a PUT to the repo's actions oidc customization sub endpoint, and "use_default" set to true resets it. GitHub's advice is to create the matching condition at the cloud provider first, because otherwise the generated token might not be accepted.
Reusable workflows can be pinned too. If you include job_workflow_ref in the claim keys, the sub contains the reusable workflow path, so you can trust a specific shared workflow rather than any workflow in a repository.
Steps to write a tight rule
- Decide which jobs genuinely need cloud access. Usually deploy jobs only.
- Attach those jobs to a protected environment.
- Write the trust rule with an exact match on the environment sub, not a wildcard.
- Add the audience condition for your provider.
- Test that a pull request job and a job on another branch are both refused.
- Review the rule when repositories are renamed, moved, or consolidated.
Quick check
Does a job with an environment on the main branch use the branch format?
No. When a job references an environment, the sub uses the environment format.
Is one condition enough?
GitHub says you must define at least one, but a single loose condition, such as a wildcard on the repository, still trusts every branch and pull request. Match as exactly as your workflow allows.
Can I rename an environment safely?
Only if you update the trust rule at the same time, since the environment name is part of the sub string.
Safeguard policies and gates can review pull requests that touch workflow files, and compliance and evidence automation can record who approved a change to a trust rule. A free scan is at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.