setup-token OAuth token returns 401 Invalid bearer token with claude -p on Max subscription (interactive login on same account works)

Resolved 💬 2 comments Opened Jun 4, 2026 by greegorij 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)
  • --bare not used; ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN both unset

Steps to reproduce

  1. On macOS: claude setup-token -> browser login (the only account, Max) -> token sk-ant-oat01-... (79 chars)
  2. export CLAUDE_CODE_OAUTH_TOKEN=<token>
  3. 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_TOKEN and ANTHROPIC_API_KEY are unset.
  • --bare mode: not used (OAuth is not being skipped).
  • Decisive check: the same account via normal interactive claude.ai login (credential in ~/.claude) runs claude -p "AUTH OK" successfully. So headless -p on the subscription works in general — only the setup-token token 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 the setup-token path fails.
  • #54738 — two-line token wrap (ruled out here; token is full length).

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗