Skip to content

feat(proxy): Anthropic Claude OAuth upstream adapter - #58647

Open
demi-hl wants to merge 1 commit into
NousResearch:mainfrom
demi-hl:feat/proxy-anthropic-oauth
Open

feat(proxy): Anthropic Claude OAuth upstream adapter#58647
demi-hl wants to merge 1 commit into
NousResearch:mainfrom
demi-hl:feat/proxy-anthropic-oauth

Conversation

@demi-hl

@demi-hl demi-hl commented Jul 5, 2026

Copy link
Copy Markdown

What

Adds --provider anthropic to hermes proxy, forwarding Anthropic Messages API requests using Hermes-managed Anthropic OAuth credentials (Claude Pro/Max). Local apps can then hit Claude through the proxy with any bearer token — the same "attach real credentials to a dummy-auth request" pattern the existing nous and xai upstreams already provide.

Why it needs more than a bearer swap

Unlike the OpenAI-compatible providers, Anthropic's OAuth endpoint rejects/misroutes subscription tokens unless the request also carries:

  1. the OAuth beta/version/user-agent headers, and
  2. a system prompt that leads with the Claude Code identity block.

To support that without touching the other adapters, this adds two small opt-in hooks to the proxy server, both defaulting to no-op via getattr (nous/xai are byte-for-byte unaffected):

  • extra_headers(cred) -> dict — merged into the forwarded headers.
  • transform_body(rel_path, body) -> bytes — rewrite the request body (here: prepend the Claude Code system block, idempotently — already-prefixed requests are not double-prefixed).

x-api-key strip

The forward path already strips/replaces inbound authorization. This also strips inbound x-api-key, because the proxy always supplies its own credential — and a stale client x-api-key otherwise takes precedence at Anthropic and 401s the OAuth call. No-op for nous/xai (they never receive one).

Adapter

AnthropicOAuthAdapter reuses the existing agent.credential_pool (load_pool / select / try_refresh_current / mark_exhausted_and_rotate on 401|429), mirroring the xai adapter's shape. Only /messages is in allowed_paths (Anthropic OAuth does not serve the /chat/completions surface).

Files

  • hermes_cli/proxy/adapters/anthropic.py (new)
  • hermes_cli/proxy/server.py — two opt-in hooks + x-api-key strip
  • hermes_cli/proxy/adapters/__init__.py — register in ADAPTERS

Testing

  • py_compile clean on all three files.
  • ADAPTERS resolves ['anthropic', 'nous', 'xai'].
  • End-to-end verified against live Anthropic OAuth: external client with a dummy bearer → real claude-haiku-4-5 / claude-sonnet-4-5 200s (service_tier: standard), headers injected and system block prepended by the hooks.
  • No credentials in the diff; everything is resolved from the pool at runtime.

Adds `--provider anthropic` to `hermes proxy`, forwarding Anthropic
Messages API requests using Hermes-managed Anthropic OAuth credentials
(Claude Pro/Max), so local apps can hit Claude through the proxy with any
bearer token — same pattern as the existing nous/xai upstreams.

Anthropic's OAuth endpoint needs more than a bearer swap, so this adds two
small, opt-in adapter hooks to the proxy server (both default to no-op, so
nous/xai are unaffected):

  - extra_headers(cred): inject the OAuth beta/version/user-agent headers.
  - transform_body(path, body): prepend the Claude Code system identity
    block, which the OAuth endpoint expects on subscription tokens.

Also strips inbound `x-api-key` alongside `authorization` in the forward
path — the proxy always supplies its own credential, and a stale client
x-api-key otherwise takes precedence at Anthropic and 401s the OAuth call.

Adapter reuses the existing agent.credential_pool (load/select/refresh/
rotate on 401|429), mirroring the xai adapter. Only /messages is forwarded.
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard area/auth Authentication, OAuth, credential pools provider/anthropic Anthropic native Messages API labels Jul 5, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for extending the subscription proxy to a concrete Anthropic OAuth use case.

Problems

  • tests/hermes_cli/test_proxy.py:51-53 currently requires get_adapter("anthropic") to raise. This PR registers anthropic but changes no tests, so the existing suite will fail.
  • The adapter selects from the shared anthropic pool without filtering to OAuth. agent/credential_pool.py:92-93 supports both OAuth and API-key entries, and CredentialPool.select() (agent/credential_pool.py:1419-1421) has no auth-type filter. An API-key entry could be sent as Bearer through the OAuth masquerade path.
  • Native OAuth requests include x-app: cli alongside the beta and user-agent headers (agent/anthropic_adapter.py:818-823); the new hook omits it.
  • The feature changes the proxy's documented pass-through contract, but website/docs/user-guide/features/subscription-proxy.md:185-203 and the static provider help in hermes_cli/subcommands/gateway.py:321-325 are not updated.

Suggested changes

  • Add hermetic proxy tests, filter selection/rotation to OAuth entries, align the full OAuth header set with agent/anthropic_adapter.py, and update the proxy docs/help for native Messages API usage.

Automated hermes-sweeper review.

@@ -16,6 +17,7 @@
ADAPTERS: Dict[str, Type[UpstreamAdapter]] = {
"nous": NousPortalAdapter,
"xai": XAIGrokAdapter,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This registration invalidates the current expectation in tests/hermes_cli/test_proxy.py:51-53 that get_adapter("anthropic") raises. Please update that test and add coverage for the new adapter; this PR currently changes no test files.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 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/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have provider/anthropic Anthropic native Messages API sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants