Description
Claude Code CLI does not auto-refresh OAuth tokens when running on a headless Linux server (GCP VM). The .credentials.json file contains a valid refreshToken, but when the accessToken expires, the CLI returns a 401 instead of refreshing.
Steps to reproduce
- Run
claude login interactively on a server, authenticate via browser
- Wait for
accessToken to expire (~6 hours, expiresAt in .credentials.json)
- Run
claude -p "hello" --output-format stream-json --verbose --dangerously-skip-permissions
- Expected: token auto-refreshes using
refreshToken
- Actual:
401 authentication_error "Invalid authentication credentials"
Environment
- Claude Code version: 2.1.114
- OS: Debian 12 (GCP e2-micro VM, headless, no X/display)
.credentials.json has valid refreshToken and subscriptionType: "max"
- No browser available (headless server)
Context
Running Claude Code as a backend agent (called via -p mode from a FastAPI app). The CLI works perfectly when the token is fresh, but silently fails after expiry. Manual token refresh via the OAuth endpoint returns 403 (Cloudflare blocks non-browser requests).
Expected behavior
The CLI should auto-refresh the token using the refreshToken in .credentials.json, similar to how the interactive CLI handles it on desktop machines.
Workaround
Currently falling back to a different agent framework (Kenzan) when OAuth is expired, but this means losing access to Claude Code's full toolset (Read, Write, Edit, Bash).
Description
Claude Code CLI does not auto-refresh OAuth tokens when running on a headless Linux server (GCP VM). The
.credentials.jsonfile contains a validrefreshToken, but when theaccessTokenexpires, the CLI returns a 401 instead of refreshing.Steps to reproduce
claude logininteractively on a server, authenticate via browseraccessTokento expire (~6 hours,expiresAtin.credentials.json)claude -p "hello" --output-format stream-json --verbose --dangerously-skip-permissionsrefreshToken401 authentication_error "Invalid authentication credentials"Environment
.credentials.jsonhas validrefreshTokenandsubscriptionType: "max"Context
Running Claude Code as a backend agent (called via
-pmode from a FastAPI app). The CLI works perfectly when the token is fresh, but silently fails after expiry. Manual token refresh via the OAuth endpoint returns 403 (Cloudflare blocks non-browser requests).Expected behavior
The CLI should auto-refresh the token using the
refreshTokenin.credentials.json, similar to how the interactive CLI handles it on desktop machines.Workaround
Currently falling back to a different agent framework (Kenzan) when OAuth is expired, but this means losing access to Claude Code's full toolset (Read, Write, Edit, Bash).