Skip to content

claude-review 401s on App token exchange for Copilot-authored PRs #84

Description

@d-morrison

Summary

The Claude Code Review workflow fails before Claude ever runs
when the pull request was opened by the Copilot coding agent.
The Claude action obtains an OIDC token successfully,
then fails to exchange it for a GitHub App token:

Requesting OIDC token...
OIDC token successfully obtained
Exchanging OIDC token for app token...
App token exchange failed: 401 Unauthorized - User does not have write access on this repository

The exchange is retried twice more and the job fails after about 25 seconds.

Evidence

Failing run:
https://github.com/UCD-SERG/ucd-serg.github.io/actions/runs/30529959398
(claude-review job, 2026-07-30T09:15:33Z -> 09:15:58Z, conclusion failure).

Run metadata:

field value
event pull_request
triggering_actor Copilot
head_branch copilot/fix-claude-review-job
head_repository UCD-SERG/ucd-serg.github.io

Diagnosis

The App token exchange gates on whether the triggering actor
has write access to the repository.
The triggering actor here is the Copilot coding agent,
which is not in the repository's collaborator list,
so the exchange returns 401 and the job dies before any model call.

For contrast, run
30509709695
on the same repo logged Actor has write access: write and got past this step,
failing later for an unrelated reason
(Command failed: git fetch origin --depth=20 pull/77/head:main).
So the 401 tracks the actor, not the repository configuration.

Note on PR #83

#83
is already open against this,
titled "Fix claude-review workflow: switch to pull_request_target for fork PR support".
Its stated premise looks wrong:
the failing run's head_repository is UCD-SERG/ucd-serg.github.io itself,
not a fork,
so this is not a fork-PR problem.

That matters because pull_request_target is not a neutral swap.
It runs in a write-privileged context against the head branch's code,
which is the standard privilege-escalation footgun for that trigger,
and it would not by itself change whether the Copilot actor has write access.
Worth confirming the diagnosis before merging that approach.

Possible resolutions

Not yet decided, listing options rather than recommending one:

  • Skip the review job when the triggering actor is a known bot
    that cannot hold write access.
  • Grant the Copilot agent write access,
    if that is acceptable for this repository.
  • Have the review path use a token that does not depend on the triggering
    actor's permissions.

Scope

Filed as a tracking issue only, per our report-mistakes-proactively rule.
Found while auditing which repositories hold a CLAUDE_CODE_OAUTH_TOKEN secret;
this is unrelated to the Claude credential itself,
which never got used on this run.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions