anthropics / anthropics/claude-code-action

OIDC token exchange fails with 401 when `github.actor` is `Copilot`

Open
#1,017 2 comments 1 reaction 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.