OAuth token refresh fails in non-interactive/headless mode
Description
OAuth access tokens expire and are not refreshed when Claude Code is invoked non-interactively (e.g., via -p with --output-format json). This causes 401 authentication_error failures after ~10-15 minutes of usage.
Reproduction
- Authenticate with
claude /login(OAuth flow) - Run Claude Code in a loop via a script that invokes it non-interactively:
````
claude -p "do something" --output-format stream-json --resume <session_id>
- After the OAuth access token expires (~10-15 min), the next invocation fails with:
````
authentication_error: OAuth token has expired. Please obtain a new token or refresh your existing token.
Expected behavior
The CLI should automatically refresh the OAuth token using the refresh token, the same way it does in interactive mode.
Actual behavior
The CLI returns a 401 error and exits. The user must manually run claude /login again to re-authenticate.
Context
This is particularly painful for automation use cases where Claude Code is invoked repeatedly in a loop by an orchestrator script. The token expires mid-run and kills the entire loop silently.
Environment
- Claude Code version: 2.1.59
- macOS (Darwin 25.2.0)
- Auth method: OAuth (Claude Max subscription)
- Invocation: non-interactive via
-pflag with--output-format stream-json
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗