anthropics / anthropics/claude-code-action
OIDC token exchange fails with 401 when `github.actor` is `Copilot`
- Dominant language
- TypeScript
- Stars
- 8.9k
- Forks
- 2.1k
- Avg merge
- 3d 9h
- Merged PRs (30d)
- 10
Description
## Describe the bug
When a `pull_request_review` event is triggered by GitHub Copilot, the OIDC token exchange at `https://api.anthropic.com/api/github/github-app-token-exchange` fails with `401 Unauthorized - User does not have write access on this repository`.
This happens because GitHub sets `github.actor` to `Copilot` for Copilot-initiated reviews. The OIDC token embeds this as the actor claim, and the Anthropic server-side validation rejects it because `Copilot` is not a regular GitHub user with repository permissions.
## To Reproduce
1. Have `anthropics/claude-code-action@v1` configured on a `pull_request_review` workflow
2. Request a review from GitHub Copilot on a PR
3. Copilot submits a review, triggering the workflow with `github.actor = "Copilot"`
4. The OIDC token is obtained successfully, but the app token exchange fails
## Error Log
```
Auto-detected mode: agent for event: pull_request_review
Requesting OIDC token...
Attempt 1 of 3...
OIDC token successfully obtained
Exchanging OIDC token for app token...
Attempt 1 of 3...
App token exchange failed: 401 Unauthorized - User does not have write access on this repository
Attempt 1 failed: User does not have write access on this repository
Retrying in 5 seconds...
...
Operation failed after 3 attempts
Error: Action failed with error: User does not have write access on this repository
```
## Comparison
An earlier run on the **same branch and workflow** triggered by a human review (`github.actor = "goodtune"`) succeeded without issue:
| | Failing Run | Successful Run |
|---|---|---|
| **`actor`** | `Copilot` | `goodtune` |
| **`triggering_actor`** | `goodtune` | `goodtune` |
| **OIDC token** | Obtained | Obtained |
| **App token exchange** | 401 rejected | Succeeded |
- Failing run: https://github.com/goodtune/ghp/actions/runs/22727204448/job/65936935451
- Successful run: https://github.com/goodtune/ghp/actions/runs/22726655285
## Root Cause
The error originates **server-side** at Anthropic's `github-app-token-exchange` endpoint, not in the action client code. The server validates the `actor` claim from the OIDC token and rejects it because `Copilot` doesn't have write access to the repository.
The `triggering_actor` (the human who owns the repo) does have write access, but the server appears to only check `actor`.
## Workaround
Mint a GitHub App installation token separately and pass it via the `github_token` input, bypassing the OIDC exchange entirely:
```yaml
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Respond to review
uses: anthropics/claude-code-action@v1
with:
github_token: ${{ steps.app-token.outputs.token }}
# ... other inputs
```
**Note:** when using this workaround, you should also remove `id-token: write` from the workflow permissions to avoid leaking OIDC environment variables into the action context (see #1010).
**Note:** even with this workaround, a second bug in `checkWritePermissions()` causes a 404 when looking up the `Copilot` actor — see #1018.
## Related Issues
- #903 — Same root problem (Copilot as actor) but reports a different error point (`checkHumanActor` 404)
- #900 — Similar `checkHumanActor` 404 for bot actors in scheduled workflows
- #93 — Closed as wontfix, proposed skipping permission checks in review mode
- #1010 — OIDC token env vars leaked to Claude session
## Expected Behavior
The token exchange should succeed when the `triggering_actor` has write access, even if the `actor` is a non-user entity like `Copilot`. Alternatively, the action should recognise known non-user actors and handle them before attempting the exchange.
## API Provider
- [x] Anthropic First-Party API (default)
Contributor guide
Research direction
Start with the pull_request_review workflow and the OIDC exchange at https://api.anthropic.com/api/github/github-app-token-exchange, comparing the failing Copilot actor with the successful human actor described in the issue. Done means the exchange succeeds when triggering_actor has write access, or the action clearly handles non-user actors; the issue notes a separate checkWritePermissions() problem in #1018 and provides a GitHub App token workaround.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github-actions, typescript
- Domain
- authentication, ci-cd
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100