Skip to content

fix(anthropic): prevent silent auth failure after successful OAuth flow - #10664

Closed
ajmeese7 wants to merge 2 commits into
NousResearch:mainfrom
ajmeese7:fix/anthropic-auth-silent-failure
Closed

ajmeese7 wants to merge 2 commits into
NousResearch:mainfrom
ajmeese7:fix/anthropic-auth-silent-failure

Conversation

@ajmeese7

@ajmeese7 ajmeese7 commented Apr 16, 2026

Copy link
Copy Markdown

What does this PR do?

Fixes a bug where 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. 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

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • agent/anthropic_adapter.py:

    • Added write_hermes_oauth_credentials() to persist Hermes-managed PKCE tokens to ~/.hermes/.anthropic_oauth.json
    • Added _resolve_hermes_oauth_token_from_credentials() to read/validate/refresh tokens from that file
    • resolve_anthropic_token() now checks Hermes PKCE store as priority 1, before env vars and Claude Code credential files
    • run_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 checking is_claude_code_token_valid()
  • hermes_cli/auth_commands.py:

    • hermes auth add anthropic (PKCE flow) now persists credentials to ~/.hermes/.anthropic_oauth.json via write_hermes_oauth_credentials()
  • hermes_cli/main.py:

    • _activate_claude_code_credentials_if_available() in the hermes model Anthropic flow now uses _resolve_claude_code_token_from_credentials() which actually attempts token refresh — instead of accepting "refresh token exists" as proof of validity
  • hermes_cli/runtime_provider.py:

    • Improved error message for Anthropic auth failures to distinguish between "Claude Code is not logged in" and "Hermes cannot resolve a usable runtime token from its credential sources"

How to Test

  1. Start with no Anthropic credentials configured (hermes auth shows empty anthropic pool)
  2. Run hermes model, select Anthropic, choose "Claude Pro/Max subscription (OAuth login)"
  3. Complete the claude setup-token flow
  4. Verify Hermes either:
    • Successfully links Claude Code credentials and can resolve a runtime token, OR
    • Falls through to the manual token paste prompt instead of falsely claiming success
  5. After model selection completes, verify hermes chat -q "hello" works with the Anthropic provider (no auth error)

To test the PKCE path specifically:

  1. Run hermes auth add anthropic and complete the OAuth flow
  2. Verify ~/.hermes/.anthropic_oauth.json was created with valid tokens
  3. Verify hermes auth shows the anthropic credential in the pool

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Ubuntu (DEV-TUX)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Screenshots / Logs

Before fix — hermes model Anthropic OAuth reports success, then runtime fails:

✓ Claude Code credentials linked.
  Hermes will use Claude's credential store directly instead of copying a setup-token into ~/.hermes/.env.

Default model set to: claude-opus-4-6 (via Anthropic)

⚠️ Provider authentication failed: No Anthropic credentials found.

After fix — Hermes either resolves a usable token or falls through to manual paste instead of lying about success.

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"
@ajmeese7
ajmeese7 force-pushed the fix/anthropic-auth-silent-failure branch from b77610b to 283da75 Compare April 16, 2026 02:46
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks @ajmeese7. Closing — implementation plan targets infrastructure that no longer exists on current main.

Your PR introduces write_hermes_oauth_credentials() and _resolve_hermes_oauth_token_from_credentials() against ~/.hermes/.anthropic_oauth.json. That's the Hermes-native PKCE credentials store that was removed by #3107 ("chore: remove unused Hermes-native PKCE OAuth flow") — the current design uses the Claude Code credentials file at ~/.claude/.credentials.json + macOS Keychain (see #15175 for Keychain support).

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 resolve_anthropic_token() to confirm the newly-written ~/.claude/.credentials.json produces a usable token before reporting "✓ Claude Code credentials linked". Happy to review if you want to resubmit with that approach.

@teknium1 teknium1 closed this Apr 24, 2026
@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround provider/anthropic Anthropic native Messages API area/auth Authentication, OAuth, credential pools comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard labels Apr 24, 2026
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 comp/cli CLI entry point, hermes_cli/, setup wizard P1 High — major feature broken, no workaround provider/anthropic Anthropic native Messages API type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants