Skip to content

feat: full Claude Code OAuth provider support#518

Open
blackopsrepl wants to merge 1 commit intoRightNow-AI:mainfrom
blackopsrepl:fix/claude-code-oauth-routing
Open

feat: full Claude Code OAuth provider support#518
blackopsrepl wants to merge 1 commit intoRightNow-AI:mainfrom
blackopsrepl:fix/claude-code-oauth-routing

Conversation

@blackopsrepl
Copy link

@blackopsrepl blackopsrepl commented Mar 11, 2026

What this PR does

Adds full Anthropic support beyond the direct API key — specifically, users who authenticate via Claude Code (OAuth) can now use their existing Claude Code session as the LLM backend, without needing a separate ANTHROPIC_API_KEY.

Previously the only way to use Anthropic models was a raw API key. This PR adds a second path: if you have Claude Code installed and authenticated, OpenFang can delegate all LLM calls to the claude CLI subprocess, which handles auth internally.

How it works

When the user selects Anthropic in the init wizard and chooses "Claude Code OAuth", the wizard now writes provider = "claude-code" to config instead of provider = "anthropic". This routes all requests through ClaudeCodeDriver (which shells out to claude -p) rather than hitting api.anthropic.com directly with a Bearer token — which Anthropic's API rejects.

Changes

  • init_wizard.rs — OAuth auth method picker (API key vs Claude Code OAuth), use_claude_code_oauth state flag, correct provider written to config, auto-detection of existing Claude Code credentials
  • drivers/mod.rs — remove the OAuth token fallback from the anthropic branch (it never worked; AnthropicDriver only supports API keys)
  • drivers/anthropic.rs — remove dead AuthMode::OAuth / new_oauth() / Bearer header code
  • drivers/claude_code.rs — three runtime fixes required to make the driver actually work:
    • Unset CLAUDECODE env var before spawning (CLI refuses to run in nested sessions)
    • Fix stream parser: current CLI emits message.content[{type,text}] blocks, not a flat string
    • Fix complete() parser: same nested block-array format for JSON output

Test plan

  • openfang init → Anthropic → Claude Code OAuth → model list shows claude-code models
  • ~/.openfang/config.toml has provider = "claude-code"
  • Messages return responses (no "OAuth not supported" error)
  • Anthropic with ANTHROPIC_API_KEY still works normally

@blackopsrepl blackopsrepl marked this pull request as draft March 11, 2026 13:45
Anthropic's API rejects Bearer tokens with "OAuth authentication is not
supported". The init wizard was writing provider="anthropic" when the user
chose Claude Code OAuth, sending requests through AnthropicDriver with a
Bearer header — causing every message to fail.

Additionally, the ClaudeCodeDriver had three independent bugs preventing it
from working at all:
- Subprocess crashed with "cannot launch inside another Claude Code session"
  because the CLAUDECODE env var was inherited
- Stream parser expected a flat content string but the CLI emits a nested
  message.content[{type,text}] block array
- complete() JSON parser typed content as String, failing to deserialize the
  block array format

- Add AnthropicAuthMode enum (Pick / EnterKey / OAuthReady / OAuthMissing)
  with full UI flow: method picker → key entry or OAuth confirmation screen
- Add use_claude_code_oauth: bool to State; set on OAuthReady confirm
- Add load_models_for_provider_name() helper to load catalog by name string
  (used when provider name diverges from the selected PROVIDERS entry)
- OAuthReady + Enter: set use_claude_code_oauth=true, load claude-code models,
  advance to Model step
- Provider Enter: detect OAuth-only case (no ANTHROPIC_API_KEY env var but
  credentials file present) and route directly to claude-code without showing
  ApiKey step
- save_config(): branch on use_claude_code_oauth → write provider="claude-code"
  with empty api_key_env instead of provider="anthropic"
- Reset use_claude_code_oauth on all back-navigation paths

- Remove Priority 3 OAuth fallback from the anthropic branch; AnthropicDriver
  now only accepts ANTHROPIC_API_KEY, never a Bearer token
- Update error message accordingly

- Remove AuthMode::OAuth variant, new_oauth() constructor, and OAuth arm of
  apply_auth_headers() — dead code after the above change

- Unset CLAUDECODE env var before spawning subprocess (fixes nested-session crash)
- Fix ClaudeStreamEvent: add message: Option<serde_json::Value> field to capture
  the nested assistant event format; split "assistant" arm to extract text from
  message.content[].text blocks
- Fix ClaudeJsonOutput: change content field from Option<String> to
  Option<serde_json::Value>; parse both string and block-array formats
@blackopsrepl blackopsrepl force-pushed the fix/claude-code-oauth-routing branch from 5e25f31 to 9eafeb9 Compare March 11, 2026 13:51
@blackopsrepl blackopsrepl marked this pull request as ready for review March 11, 2026 14:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant