anthropics / anthropics/claude-code

WIF: token-exchange assertions are single-use (undocumented) — shared identity-token file + another consumer ⇒ opaque 401 with a misleading hint

Aperta
#89,095 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub
area:auth bug has repro platform:linux
Lingua principale
Python
Stelle
145k
Fork
23.1k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

## Summary

`POST /v1/oauth/token` (Workload Identity Federation) enforces **one-time use per assertion**: exchanging the same OIDC JWT a second time returns `401 authentication_error: Authentication failed`. This is not mentioned in the WIF docs, and the CLI's error hint ("Ensure your federation rule matches your identity token") points at rule matching, which sends users down the wrong path. Found while migrating GitHub Actions agent workflows to keyless auth; it cost a full day of forensics.

## Reproduction (GitHub Actions, any repo with a working federation rule)

```bash
JWT=$(curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://api.anthropic.com" | jq -r .value)
# same body twice:
curl -s https://api.anthropic.com/v1/oauth/token -H content-type:application/json -d "{\"grant_type\":\"urn:ietf:params:oauth:grant-type:jwt-bearer\",\"assertion\":\"$JWT\",\"federation_rule_id\":\"fdrl_…\",\"organization_id\":\"…\",\"service_account_id\":\"svac_…\",\"workspace_id\":\"wrkspc_…\"}"
# -> 200, access_token
# (repeat the identical request)
# -> 401 {"error":{"type":"authentication_error","message":"Authentication failed"}}
```

Observed consistently on 2026-08-23 (JWT age 0–90s made no difference; body/headers/transport identical between the two calls).

## How this bites Claude Code users

The WIF reference says the SDK "re-reads `ANTHROPIC_IDENTITY_TOKEN_FILE` on every exchange so that projected tokens that rotate on disk are always current", and Claude Code (`claude-cli/2.1.241`, headless `-p`) follows the same pattern. If **anything else** exchanges the assertion in that file first — in our case a setup step that validated the federation chain eagerly — Claude Code reads an already-consumed assertion and fails with:

```
API Error: Token exchange failed with status 401 (request-id …): {"error":{"type":"authentication_error","message":"Authentication failed"}} Ensure your federation rule matches your identity token.
```

It then retries the same in-memory assertion for ~3 minutes (every retry is a replay, so every retry fails) before giving up. Nothing in the message suggests replay.

## Asks

1. **Document the single-use property** in the WIF reference (validation rules / troubleshooting) and in the token-file guidance: one consumer per assertion; mint a separate assertion for any additional exchanger.
2. **Make the CLI hint replay-aware** — e.g. "…or the identity token was already exchanged (assertions are single-use)". Ideally the CLI re-reads the token file between retries, so a rotating file self-heals instead of replaying the same burned assertion.
3. (Nice to have) Surface `replay`/`assertion_reused` as a distinct deny reason where deny reasons are recorded.

## Environment

- `@anthropic-ai/claude-code` 2.1.241 (native binary), headless `-p` mode
- GitHub Actions self-hosted runners (Linux x64), GitHub OIDC issuer, discovery-mode JWKS
- Federation rule: exact-subject match, audience `https://api.anthropic.com`, single workspace, default token lifetime

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Direzione di ricerca

Start with the WIF reference and token-file guidance, then inspect Claude Code's token-exchange retry and error-hint entry points. Reproduce the first successful exchange and subsequent 401 with the same assertion. Done should include documented single-use assertions and a replay-aware CLI path, with token-file re-reading considered between retries.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
github-actions
Ambito
authentication, cli, documentation
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Attiva
Chiarezza
Abbastanza chiara
Idoneità per principianti
52/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.