github-actions changedmanage-claude/wif-providers/github-actions
Nearest release: v2.1.319, published 17 hours before this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Recorded here
Lines+39added
Lines−37removed
From line
4
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits16to this page, all time
The whole hunk
from line 4, old and new numbered
/
from line 4
44description: Authenticate GitHub Actions workflows to the Claude API with short-lived identity tokens instead of long-lived API keys.
55---
66
7Every GitHub Actions workflow run can request a signed identity token from GitHub’s hosted issuer at `https://token.actions.githubusercontent.com`. With Workload Identity Federation, your workflow exchanges that token for a short-lived Anthropic access token, so your CI jobs can call the Claude API without an `ANTHROPIC_API_KEY` secret stored in your repository.
7Every GitHub Actions workflow run can request a signed identity token from GitHub’s hosted issuer at `https://token.actions.githubusercontent.com`. With Workload Identity Federation (WIF), your workflow exchanges that token for a short-lived Anthropic access token. Your CI jobs can then call the Claude API without an `ANTHROPIC_API_KEY` secret stored in your repository.
88
9The token’s `sub` claim encodes the repository and trigger context. For a push to a branch it has the form `repo:<owner>/<repo>:ref:refs/heads/<branch>`. Pull-request runs use `repo:<owner>/<repo>:pull_request`, and environment-gated deployments use `repo:<owner>/<repo>:environment:<name>`. Your federation rule matches against this claim (and others, such as `repository_owner` and `ref`) to determine which workflow runs are allowed to authenticate.
9The token’s `sub` claim encodes the repository and trigger context. For a push to a branch it has the form `repo:<owner>/<repo>:ref:refs/heads/<branch>`. Pull-request runs use `repo:<owner>/<repo>:pull_request`, and environment-gated deployments use `repo:<owner>/<repo>:environment:<name>`. Your federation rule matches against this claim (and others, such as `repository_owner` and `ref`) to determine which workflow runs can authenticate.
1010
1111## Prerequisites
1212
from line 25
2525 contents: read
2626```
2727
28Inside the job, the runner exposes two environment variables: `ACTIONS_ID_TOKEN_REQUEST_URL` and `ACTIONS_ID_TOKEN_REQUEST_TOKEN`. Call the request URL with the request token as a bearer credential and your chosen audience as a query parameter, then write the returned JSON Web Token (JWT) to a file:
28Inside the job, the runner exposes two environment variables: `ACTIONS_ID_TOKEN_REQUEST_URL` and `ACTIONS_ID_TOKEN_REQUEST_TOKEN`. Call the request URL with the request token as a bearer credential and your chosen audience as a query parameter. Then write the returned JSON Web Token (JWT) to a file:
2929
3030```yaml
3131- name: Fetch GitHub OIDC token
from line 105
105105}
106106```
107107
108Be as specific as the workload allows. Loosen `subject_prefix` to `repo:your-org/your-repo:*` (paired with a `claims.ref` constraint) only if the rule must match multiple event types from the same repository, because the trailing segment of `sub` varies among `ref:...`, `environment:...`, and `pull_request` events.
108Be as specific as the workload allows. Loosen `subject_prefix` to `repo:your-org/your-repo:*` (paired with a `claims.ref` constraint) only if the rule must match multiple event types from the same repository. The trailing segment of `sub` varies among `ref:...`, `environment:...`, and `pull_request` events.
109109
110110## Acquire and use a token
111111
112Set the federation environment variables on the job. In the SDK, `anthropic.Anthropic()` (typescript: `new Anthropic()`; csharp: `new AnthropicClient()`; go: `anthropic.NewClient()`; java: `AnthropicOkHttpClient.fromEnv()`; php: `new Client()`; ruby: `Anthropic::Client.new`) reads `ANTHROPIC_IDENTITY_TOKEN_FILE`, exchanges the JWT on the first request, and refreshes the access token automatically before it expires.
112Set the federation environment variables on the job, and write GitHub’s OIDC token to the file that `ANTHROPIC_IDENTITY_TOKEN_FILE` names:
113113
114<CodeGroup>
115 ```yaml Workflow
116 name: Call Claude
117 on: push
114```yaml
115name: Call Claude
116on: push
118117
119 permissions:
120 id-token: write
121 contents: read
118permissions:
119 id-token: write
120 contents: read
122121
123 jobs:
124 call-claude:
125 runs-on: ubuntu-latest
126 env:
127 ANTHROPIC_FEDERATION_RULE_ID: fdrl_...
128 ANTHROPIC_ORGANIZATION_ID: 00000000-0000-0000-0000-000000000000
129 ANTHROPIC_SERVICE_ACCOUNT_ID: svac_...
130 ANTHROPIC_WORKSPACE_ID: wrkspc_... # required when the rule covers multiple workspaces
131 ANTHROPIC_IDENTITY_TOKEN_FILE: /tmp/gha-jwt
132 steps:
133 - uses: actions/checkout@v5
134 - name: Fetch GitHub OIDC token
135 run: |
136 curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
137 "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://api.anthropic.com" \
138 | jq -r .value > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
139 - name: Run your script
140 run: |
141 pip install anthropic
142 python your_script.py
143 ```
122jobs:
123 call-claude:
124 runs-on: ubuntu-latest
125 env:
126 ANTHROPIC_FEDERATION_RULE_ID: fdrl_...
127 ANTHROPIC_ORGANIZATION_ID: 00000000-0000-0000-0000-000000000000
128 ANTHROPIC_SERVICE_ACCOUNT_ID: svac_...
129 ANTHROPIC_WORKSPACE_ID: wrkspc_... # required when the rule covers multiple workspaces
130 ANTHROPIC_IDENTITY_TOKEN_FILE: /tmp/gha-jwt
131 steps:
132 - uses: actions/checkout@v5
133 - name: Fetch GitHub OIDC token
134 run: |
135 curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
136 "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://api.anthropic.com" \
137 | jq -r .value > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
138 - name: Run your script
139 run: |
140 pip install anthropic
141 python your_script.py
142```
144143
144Then call the Claude API from your script. An SDK client that you create without credentials reads `ANTHROPIC_IDENTITY_TOKEN_FILE`, exchanges the JWT on the first request, and refreshes the access token automatically before it expires.
145
146<CodeGroup>
145147 ```bash cURL
146148 JWT=$(cat /tmp/gha-jwt)
147149
from line 315
313315
314316## Verify the setup
315317
316A successful exchange returns an `access_token` starting with `sk-ant-oat01-` and an `expires_in` value in seconds. A denied exchange returns an opaque `401` `authentication_error` with the fixed message `Authentication failed`, whichever check failed. In most cases the deny reason is recorded on the attempt’s entry in the [authentication history page](https://platform.claude.com/settings/workload-identity-federation?tab=history) in the Claude Console. [Troubleshoot a failed exchange](https://platform.claude.com/docs/en/manage-claude/wif-reference#troubleshoot-a-failed-exchange) walks the checks in order. The most common GitHub Actions-side cause is the `sub` claim format not matching (its trailing segment varies among `ref:...`, `environment:...`, and `pull_request` events); the history entry shows reason `match_subject_prefix`.
318A successful exchange returns an `access_token` starting with `sk-ant-oat01-` and an `expires_in` value in seconds. A denied exchange returns an opaque `401` `authentication_error` with the fixed message `Authentication failed`, whichever check failed. In most cases, the attempt’s entry on the [authentication history page](https://platform.claude.com/settings/workload-identity-federation?tab=history) in the Claude Console shows the deny reason. [Troubleshoot a failed exchange](https://platform.claude.com/docs/en/manage-claude/wif-reference#troubleshoot-a-failed-exchange) walks through the checks in order. The most common GitHub Actions-side cause is a `sub` claim format that doesn’t match, because its trailing segment varies among `ref:...`, `environment:...`, and `pull_request` events. The history entry then shows the reason `match_subject_prefix`.
317319
318320## Restrict which workflows can authenticate
319321
No line in this hunk matches that.