Skip to content

fix(anthropic): recover Claude Code OAuth via CLI refresh fallback - #57935

Closed
woriwka-ai wants to merge 1 commit into
NousResearch:mainfrom
woriwka-ai:fix/anthropic-claude-code-cli-refresh
Closed

fix(anthropic): recover Claude Code OAuth via CLI refresh fallback#57935
woriwka-ai wants to merge 1 commit into
NousResearch:mainfrom
woriwka-ai:fix/anthropic-claude-code-cli-refresh

Conversation

@woriwka-ai

@woriwka-ai woriwka-ai commented Jul 3, 2026

Copy link
Copy Markdown

Summary

Adds a bounded last-resort recovery path for Claude Code OAuth credentials in resolve_anthropic_token():

  • keep the existing fast path: env token, CLAUDE_CODE_OAUTH_TOKEN, Claude Code credential store + pure refresh;
  • if Hermes still cannot resolve a token, run the official Claude Code CLI once with a tiny non-secret prompt;
  • re-read the Claude Code credential store and continue to credential-pool/API-key fallback if CLI recovery did not produce fresh creds;
  • throttle CLI refresh attempts with a 5-minute in-process cooldown;
  • allow operators to disable the fallback via HERMES_ANTHROPIC_DISABLE_CLAUDE_CLI_REFRESH=1.

This addresses the degraded state where both persisted Claude Code sources look expired to Hermes, Hermes' direct/pure refresh loses or is blocked, but the official claude CLI can still refresh its own Keychain/session state. In that state Hermes/Fable can fall through to No Anthropic credentials found even though claude -p ... immediately restores a usable token.

Related: #6347, #48534, #55051.

Testing

python -m py_compile agent/anthropic_adapter.py
python -m pytest tests/agent/test_anthropic_claude_code_refresh_fallback.py -q

Result:

7 passed

Live local smoke before upstreaming, with tokens redacted/not printed:

Claude Code credential source present
credentials valid
Anthropic token resolved
fable_guard=ok · smoke=ok
claude-fable-5 clean-env smoke -> OK
pytest tests/agent/test_anthropic_claude_code_refresh_fallback.py -q -> 7 passed

Safety notes

  • The CLI output is ignored and never logged, so tokens are not printed.
  • The fallback only runs after the existing direct Claude Code credential/pure-refresh path fails.
  • Nonzero/timeout/missing CLI falls through to the existing pool/API-key behavior.
  • The env kill switch prevents the CLI subprocess entirely.

@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint area/auth Authentication, OAuth, credential pools provider/anthropic Anthropic native Messages API P2 Medium — degraded but workaround exists sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data labels Jul 3, 2026
@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Thanks @woriwka-ai — appreciate the thorough recovery path. Closing in favor of a root-cause fix merged via #58178.

The underlying failure was that Hermes' own OAuth token exchange/refresh was blocked at the token endpoint: Anthropic 429s any /v1/oauth/token request whose User-Agent starts with claude-code/. Once that UA is corrected to axios/ (matching the real Claude Code CLI's exchange client), Hermes' direct refresh works again and the CLI-subprocess fallback isn't needed. Verified live: claude-code/ → 429, axios/ → 400 invalid_grant (reached validation).

Two additional reasons for the root-cause fix over the fallback here:

  • Shelling out to the claude CLI as a refresh mechanism couples Hermes' auth to an external binary and adds ~250 LOC of subprocess plumbing for a problem that's a one-line UA change at the source.
  • The HERMES_ANTHROPIC_DISABLE_CLAUDE_CLI_REFRESH env var is a behavioral (non-secret) config flag. Per our contribution rubric, .env / HERMES_* env vars are for secrets/credentials only — behavioral settings belong in config.yaml. (Not a knock on the PR — just why we don't take the flag.)

Fixed in #58178: #58178

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists provider/anthropic Anthropic native Messages API sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants