setup-token OAuth token returns 401 Invalid bearer token with claude -p on Max subscription (interactive login on same account works)
Summary
A long-lived token from claude setup-token consistently returns API Error: 401 Invalid bearer token when used via CLAUDE_CODE_OAUTH_TOKEN with claude -p, even though interactive claude.ai login on the same single account (Max plan) works fine with claude -p. This blocks running a headless agent on a subscription, which is the documented purpose of setup-token.
Environment
- Claude Code: v2.1.162
- OS: Ubuntu 24.04 (VPS) and macOS — both reproduce
- Node: v24
- Plan: Max, single Anthropic account (no other accounts)
--barenot used;ANTHROPIC_API_KEYandANTHROPIC_AUTH_TOKENboth unset
Steps to reproduce
- On macOS:
claude setup-token-> browser login (the only account, Max) -> tokensk-ant-oat01-...(79 chars) export CLAUDE_CODE_OAUTH_TOKEN=<token>claude -p "hello"
Result:
Failed to authenticate. API Error: 401 Invalid bearer token
What I ruled out
- Truncation / two-line copy-paste (#54738): token is exactly 79 chars; generated two separate tokens, both 79 -> full length, not truncated.
- Machine-specific: fails identically on the VPS and on macOS with an isolated
CLAUDE_CONFIG_DIR-> not environment-specific. - Account / plan: only one Anthropic account, Max plan, browser logged into that account during
setup-token. - Env override (#34826): both
ANTHROPIC_AUTH_TOKENandANTHROPIC_API_KEYare unset. --baremode: not used (OAuth is not being skipped).- Decisive check: the same account via normal interactive
claude.ailogin (credential in~/.claude) runsclaude -p "AUTH OK"successfully. So headless-pon the subscription works in general — only thesetup-tokentoken is rejected.
claude auth status while using the token reports:
{"loggedIn": true, "authMethod": "oauth_token", "apiProvider": "firstParty"}
i.e. the token is accepted locally but rejected by the server on the actual API call.
Expected
The setup-token token authenticates claude -p on a Max subscription, per the docs (code.claude.com/docs/en/authentication, "Generate a long-lived token").
Actual
401 Invalid bearer token on every call, on two machines, with a fresh token.
Possibly related
- #58926 — 401 auth loop, but that is Windows and all commands (incl.
/login) fail; here interactive login works and only thesetup-tokenpath fails. - #54738 — two-line token wrap (ruled out here; token is full length).
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗