setup-token generates invalid bearer token (401 Invalid bearer token)
Resolved 💬 3 comments Opened Mar 30, 2026 by sydhubsyd Closed Apr 2, 2026
Bug Description
claude setup-token generates a token that is rejected by the API with 401 Invalid bearer token when used as CLAUDE_CODE_OAUTH_TOKEN in a headless Docker environment.
Environment
- Claude Code version: 2.1.84 (VPS container), 2.1.87 (local Mac)
- OS: Ubuntu 24.04 (Docker container on Hetzner VPS)
- Subscription: Claude Max
- Auth method:
claude setup-tokenrun viassh -tinto the Docker container
Steps to Reproduce
- SSH into VPS running Paperclip (agent orchestrator) with Claude Code in a Docker container
- Run
docker exec -it paperclip claude setup-token - Complete browser OAuth flow, receive token
- Recreate container with
-e CLAUDE_CODE_OAUTH_TOKEN=<token> - Verify:
claude auth statusreportsloggedIn: true, authMethod: oauth_token - Attempt any API call:
claude -p "say hello" --max-turns 1
Expected Behaviour
API call succeeds using Max subscription via the long-lived setup-token.
Actual Behaviour
Failed to authenticate. API Error: 401
{"type":"error","error":{"type":"authentication_error","message":"Invalid bearer token"},"request_id":"req_011CZYtmP2A1Ej9Mi7Dv5NrR"}
Additional Context
claude auth statusshowsloggedIn: truewith the setup-token, but actual API calls fail- The token contains a
#character which required careful shell quoting, but the full 92-char token was verified as correctly stored in the container env var - Falling back to interactive
claude auth login(short-lived 8-12h credentials file) works perfectly with the same container and subscription - The setup-token was generated via SSH TTY (
ssh -t+docker exec -it), not on a local machine with a native browser -- this may be relevant
Workaround
Use claude auth login (interactive) instead of setup-token. This produces 8-12h tokens that work, but requires periodic re-authentication which defeats the purpose of setup-token for headless/automated environments.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗