OAuth token refresh fails in non-interactive/headless mode

Resolved 💬 4 comments Opened Feb 26, 2026 by awilkening Closed Mar 1, 2026

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

  1. Authenticate with claude /login (OAuth flow)
  2. 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>
``

  1. 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 -p flag with --output-format stream-json

View original on GitHub ↗

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