Conversation
The Anthropic OAuth flow via `hermes model` could report success
("Claude Code credentials linked") while leaving Hermes unable to
actually resolve a usable runtime token. This caused users to see
"No Anthropic credentials found" immediately after a successful
authentication ceremony.
Root causes:
1. `_run_anthropic_oauth_flow()` in main.py accepted credentials as
valid if the Claude Code credential file had a refresh token OR
the access token hadn't expired — without actually testing whether
the token could be resolved through the runtime path. An expired
token with a broken refresh flow would pass this check.
2. `run_oauth_setup_token()` checked parent-process env vars
(CLAUDE_CODE_OAUTH_TOKEN, ANTHROPIC_TOKEN) after running
`claude setup-token` as a subprocess. A child process cannot
mutate its parent's environment, so these checks were no-ops
that silently fell through to "no credentials detected."
3. `hermes auth add anthropic` (PKCE flow) stored credentials in the
credential pool but did not persist them to the Hermes-managed
PKCE file (~/.hermes/.anthropic_oauth.json). The runtime token
resolver never checked this file either, so PKCE-obtained
credentials were invisible at runtime.
4. `resolve_anthropic_token()` had no awareness of Hermes' own PKCE
credential store, only checking env vars and Claude Code's
credential file.
Changes:
- Add `write_hermes_oauth_credentials()` and
`_resolve_hermes_oauth_token_from_credentials()` to
anthropic_adapter.py for reading/writing/refreshing tokens from
~/.hermes/.anthropic_oauth.json
- `resolve_anthropic_token()` now checks Hermes PKCE store first
(priority 1), before env vars and Claude Code credential files
- `hermes auth add anthropic` now persists to the PKCE file
- `_activate_claude_code_credentials_if_available()` in the
`hermes model` flow now uses `_resolve_claude_code_token_from_credentials()`
which actually attempts refresh — instead of just checking metadata
- `run_oauth_setup_token()` no longer checks parent-process env vars
after subprocess completion; uses the same resolve path instead
- Improved error message for Anthropic auth failures to distinguish
between "Claude Code is not logged in" and "Hermes cannot resolve
a usable runtime token"
b77610b to
283da75
Compare
|
Thanks @ajmeese7. Closing — implementation plan targets infrastructure that no longer exists on current main. Your PR introduces The "silent success, runtime can't resolve a usable token" bug you identified is legitimate, but the fix on current main would be different: a post-setup validation step that calls |
What does this PR do?
Fixes a bug where the Anthropic OAuth flow via
hermes modelcould report success ("✓ Claude Code credentials linked") while leaving Hermes unable to actually resolve a usable runtime token. Users would see "No Anthropic credentials found" immediately after a successful authentication ceremony.The root cause was a gap between the setup UI's success validation (which accepted credential-shaped metadata) and the runtime token resolver (which needed an actually usable token). Four separate defects contributed to this gap — see Changes Made below.
Related Issue
Type of Change
Changes Made
agent/anthropic_adapter.py:write_hermes_oauth_credentials()to persist Hermes-managed PKCE tokens to~/.hermes/.anthropic_oauth.json_resolve_hermes_oauth_token_from_credentials()to read/validate/refresh tokens from that fileresolve_anthropic_token()now checks Hermes PKCE store as priority 1, before env vars and Claude Code credential filesrun_oauth_setup_token()no longer checks parent-process env vars after subprocess completion (child processes cannot mutate parent environment — these checks were no-ops)run_oauth_setup_token()now uses_resolve_claude_code_token_from_credentials()which attempts refresh, instead of just checkingis_claude_code_token_valid()hermes_cli/auth_commands.py:hermes auth add anthropic(PKCE flow) now persists credentials to~/.hermes/.anthropic_oauth.jsonviawrite_hermes_oauth_credentials()hermes_cli/main.py:_activate_claude_code_credentials_if_available()in thehermes modelAnthropic flow now uses_resolve_claude_code_token_from_credentials()which actually attempts token refresh — instead of accepting "refresh token exists" as proof of validityhermes_cli/runtime_provider.py:How to Test
hermes authshows empty anthropic pool)hermes model, select Anthropic, choose "Claude Pro/Max subscription (OAuth login)"claude setup-tokenflowhermes chat -q "hello"works with the Anthropic provider (no auth error)To test the PKCE path specifically:
hermes auth add anthropicand complete the OAuth flow~/.hermes/.anthropic_oauth.jsonwas created with valid tokenshermes authshows the anthropic credential in the poolChecklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AScreenshots / Logs
Before fix —
hermes modelAnthropic OAuth reports success, then runtime fails:After fix — Hermes either resolves a usable token or falls through to manual paste instead of lying about success.