setup-token OAuth token returns 401 Invalid bearer token with claude -p on Max subscription (interactive login on same account works)
Status Fixed / completed
Maintainer reply None cached
Activity 3 comments · opened Jun 4, 2026 · closed Jun 4, 2026
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).
3 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Resolved — this was a truncated token on my side, not a server bug. Confirmed duplicate of #54738.
claude setup-tokenprinted the token wrapped across two terminal lines and my copy captured only the first line. The genuine token is 108 chars; the one I tested was 79 — silently truncated at the terminal width. A second token I generated also came out 79 because it was the same terminal window wrapping at the same column, which is exactly why "both 79 chars" misled me into ruling truncation out (I never checked the true expected length).Re-copied the full value with the embedded line break removed →
claude -pnow returns successfully on the Max subscription, headless. TheloggedIn: true+ 401 combination is the tell: the bearer string is accepted locally but rejected by the server because it's incomplete.Closing as duplicate of #54738 (the real, actionable bug: setup-token should emit the token unwrapped). Thanks!
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.