← Back to brief

reference claude setup token oauth

memory · reference_claude_setup_token_oauth.md

Non-obvious core fact: claude setup-token (Claude Code v2.1.x) uses code=true OAuth. After Authorize, the browser lands on https://platform.claude.com/oauth/code/callback?code=<C>&state=<S>. The string the CLI's "Paste code here if prompted >" expects is <C>#<S> — the authorization code AND the state, joined by a literal #. The callback PAGE body spells it out: "Paste this into Claude Code: <C>#<S>". Delivering only the URL code= param (without #<S>) fails with "OAuth error: Invalid code. Please make sure the full code was copied" — the "full code" wording is literal: it means code+#+state. This cost ~6 wasted Authorize cycles on 2026-05-16 before reading the callback page body instead of just parsing the URL query.

Delivery mechanism that works (box / headless):

Linux /tmp gotchas hit along the way: fs.protected_fifos/fs.protected_regular block root doing O_CREAT on a skyrun-owned file/FIFO in sticky /tmp — rm as root first then recreate, or use os.open(path, os.O_WRONLY) (no O_CREAT). pkill -f oauth_watch run inline inside an ssh command whose own string contains "oauth_watch" self-kills the ssh shell (exit 255) — always put such pkills in a script file.

Box Max auth (installed 2026-05-16): token created (1-yr) and stored on the cloud box at ~/.config/skyrun/max_oauth_token (chmod 600, skyrun) + sourceable ~/.config/skyrun/max_env.sh (export CLAUDE_CODE_OAUTH_TOKEN=...). Headless verified: CLAUDE_CODE_OAUTH_TOKEN=$(cat ~/.config/skyrun/max_oauth_token) claude -p "..." returns answers → box runs Claude Code headlessly on Joseph's Max 20x plan, no per-token API bill. setup-token does NOT write ~/.claude/.credentials.json — it only prints the token once; capture it from the tmux pane on SETUP_EXIT=0. Renew before the 1-yr expiry (~2027-05-16) using this same procedure.