fix: use Bearer auth for ANTHROPIC_AUTH_TOKEN and add ANTHROPIC_MODEL#197
fix: use Bearer auth for ANTHROPIC_AUTH_TOKEN and add ANTHROPIC_MODEL#197worldofgeese wants to merge 1 commit intospacedriveapp:mainfrom
Conversation
- Add new AnthropicAuthPath::AuthToken variant for proxy tokens - Track is_auth_token in ProviderConfig when key comes from ANTHROPIC_AUTH_TOKEN - Pass is_auth_token through build_anthropic_request to apply_auth_headers - AuthToken uses Authorization: Bearer without Claude Code identity headers - Add ANTHROPIC_MODEL env var to set all anthropic/* routes - Update tests for new AuthToken variant Fixes 403 errors when using ANTHROPIC_AUTH_TOKEN with corporate proxies. Closes discussion in spacedriveapp#135 about auth header mismatch. Note: CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC is deferred for future work.
WalkthroughThis PR adds support for Anthropic Bearer token authentication via Changes
Sequence DiagramsequenceDiagram
participant Config as Configuration<br/>(load_from_env)
participant AuthDetect as Auth Detection<br/>(detect_auth_path)
participant AuthApply as Auth Headers<br/>(apply_auth_headers)
participant Request as Request Builder<br/>(build_anthropic_request)
Config->>Config: Determine is_auth_token<br/>(ANTHROPIC_AUTH_TOKEN present?)
Config->>Request: Pass is_auth_token flag
Request->>AuthDetect: Call with token & is_auth_token
AuthDetect->>AuthDetect: Branch: is_auth_token=true?
alt Bearer Token (AuthToken path)
AuthDetect->>AuthApply: Return AuthToken variant
AuthApply->>AuthApply: Apply Bearer Authorization<br/>header only
else API Key/OAuth (existing paths)
AuthDetect->>AuthApply: Return ApiKey/OAuthToken
AuthApply->>AuthApply: Apply existing auth headers
end
AuthApply->>Request: Return configured RequestBuilder
Request->>Request: Build complete request
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/llm/anthropic/auth.rs (1)
96-107:⚠️ Potential issue | 🟠 MajorUpdate detect_auth_path test calls for new signature.
The unit tests still call
detect_auth_pathwith one argument, so the test module won’t compile.🧪 Update test calls
- detect_auth_path("sk-ant-oat01-abc123"), + detect_auth_path("sk-ant-oat01-abc123", false), AnthropicAuthPath::OAuthToken ); } @@ - detect_auth_path("sk-ant-api03-xyz789"), + detect_auth_path("sk-ant-api03-xyz789", false), AnthropicAuthPath::ApiKey ); } @@ - detect_auth_path("some-random-key"), + detect_auth_path("some-random-key", false), AnthropicAuthPath::ApiKey ); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/llm/anthropic/auth.rs` around lines 96 - 107, Tests failing because detect_auth_path now requires a second boolean parameter is_auth_token; update all test calls to pass the appropriate is_auth_token value. Find usages in the test module that call detect_auth_path(token) and change them to detect_auth_path(token, true) or detect_auth_path(token, false) depending on whether the test intends the token to come from ANTHROPIC_AUTH_TOKEN; ensure test cases asserting AnthropicAuthPath::AuthToken use true and other cases use false.src/llm/anthropic/params.rs (1)
54-107:⚠️ Potential issue | 🟠 MajorAuthToken shouldn’t trigger Claude Code preamble/tool normalization.
is_oauthnow treatsAuthTokenlike OAuth, which injects Claude Code identity behavior and tool renaming. That contradicts the “bearer-only, no identity” intent forANTHROPIC_AUTH_TOKEN. Keep OAuth behavior only forOAuthToken(and mirror inmodel.rs).🔧 Suggested change
- let is_oauth = auth_path == AnthropicAuthPath::OAuthToken || auth_path == AnthropicAuthPath::AuthToken; + let is_oauth = auth_path == AnthropicAuthPath::OAuthToken;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/llm/anthropic/params.rs` around lines 54 - 107, The code sets is_oauth by comparing auth::detect_auth_path(...) to both AnthropicAuthPath::OAuthToken and AnthropicAuthPath::AuthToken, which causes AuthToken to receive OAuth-only behavior; change the is_oauth check in build_anthropic_request to be true only when auth::detect_auth_path(...) == AnthropicAuthPath::OAuthToken so ANTHROPIC_AUTH_TOKEN remains "bearer-only, no identity", and adjust any related logic that branches on is_oauth (e.g., build_system_prompt and build_tools calls) accordingly; also mirror this fix in the corresponding logic in model.rs where detect_auth_path is evaluated.
♻️ Duplicate comments (1)
src/llm/model.rs (1)
362-363: Align AuthToken handling with non‑OAuth tool remap.Same concern as noted in
src/llm/anthropic/params.rs: if AuthToken is meant to be bearer-only, it shouldn’t trigger Claude Code tool remapping here either.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/llm/model.rs` around lines 362 - 363, The check that sets is_oauth currently treats AnthropicAuthPath::AuthToken the same as OAuthToken; change the logic so only AnthropicAuthPath::OAuthToken makes is_oauth true (i.e., remove the AuthToken branch) so bearer-only AuthToken does not trigger Claude Code tool remapping; update the condition using anthropic_request.auth_path and the AnthropicAuthPath::OAuthToken enum variant accordingly (leave any other uses of AnthropicAuthPath::AuthToken untouched).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/config.rs`:
- Around line 2078-2086: The current boolean anthropic_is_auth_token only
becomes true when no TOML key is present, so a TOML anthropic_key that
references env:ANTHROPIC_AUTH_TOKEN still selects x-api-key; update the logic to
also detect when toml.llm.anthropic_key explicitly references the environment
variable ANTHROPIC_AUTH_TOKEN (e.g., the raw string contains or parses as
"env:ANTHROPIC_AUTH_TOKEN" or resolve_env_value indicates an env-ref) and treat
that case as using auth token; modify the condition around
anthropic_is_auth_token (and the duplicate logic at the later block around the
2218-2229 occurrence) to check both the absence of a resolved TOML key and the
presence of an env reference to ANTHROPIC_AUTH_TOKEN before consulting
std::env::var.
---
Outside diff comments:
In `@src/llm/anthropic/auth.rs`:
- Around line 96-107: Tests failing because detect_auth_path now requires a
second boolean parameter is_auth_token; update all test calls to pass the
appropriate is_auth_token value. Find usages in the test module that call
detect_auth_path(token) and change them to detect_auth_path(token, true) or
detect_auth_path(token, false) depending on whether the test intends the token
to come from ANTHROPIC_AUTH_TOKEN; ensure test cases asserting
AnthropicAuthPath::AuthToken use true and other cases use false.
In `@src/llm/anthropic/params.rs`:
- Around line 54-107: The code sets is_oauth by comparing
auth::detect_auth_path(...) to both AnthropicAuthPath::OAuthToken and
AnthropicAuthPath::AuthToken, which causes AuthToken to receive OAuth-only
behavior; change the is_oauth check in build_anthropic_request to be true only
when auth::detect_auth_path(...) == AnthropicAuthPath::OAuthToken so
ANTHROPIC_AUTH_TOKEN remains "bearer-only, no identity", and adjust any related
logic that branches on is_oauth (e.g., build_system_prompt and build_tools
calls) accordingly; also mirror this fix in the corresponding logic in model.rs
where detect_auth_path is evaluated.
---
Duplicate comments:
In `@src/llm/model.rs`:
- Around line 362-363: The check that sets is_oauth currently treats
AnthropicAuthPath::AuthToken the same as OAuthToken; change the logic so only
AnthropicAuthPath::OAuthToken makes is_oauth true (i.e., remove the AuthToken
branch) so bearer-only AuthToken does not trigger Claude Code tool remapping;
update the condition using anthropic_request.auth_path and the
AnthropicAuthPath::OAuthToken enum variant accordingly (leave any other uses of
AnthropicAuthPath::AuthToken untouched).
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/api/providers.rssrc/config.rssrc/llm/anthropic/auth.rssrc/llm/anthropic/params.rssrc/llm/manager.rssrc/llm/model.rs
| // Track whether ANTHROPIC_AUTH_TOKEN is being used (for Bearer auth) | ||
| let anthropic_is_auth_token = toml | ||
| .llm | ||
| .anthropic_key | ||
| .as_deref() | ||
| .and_then(resolve_env_value) | ||
| .is_none() | ||
| && std::env::var("ANTHROPIC_API_KEY").is_err() | ||
| && std::env::var("ANTHROPIC_AUTH_TOKEN").is_ok(); |
There was a problem hiding this comment.
Config env:ANTHROPIC_AUTH_TOKEN won’t set is_auth_token.
anthropic_is_auth_token only flips when no TOML key is present, so a config that references env:ANTHROPIC_AUTH_TOKEN will still use x‑api‑key headers. Consider detecting that env reference explicitly (or adding a config flag).
🔧 Suggested change
- let anthropic_is_auth_token = toml
- .llm
- .anthropic_key
- .as_deref()
- .and_then(resolve_env_value)
- .is_none()
- && std::env::var("ANTHROPIC_API_KEY").is_err()
- && std::env::var("ANTHROPIC_AUTH_TOKEN").is_ok();
+ let anthropic_key_raw = toml.llm.anthropic_key.as_deref();
+ let anthropic_is_auth_token =
+ matches!(anthropic_key_raw, Some("env:ANTHROPIC_AUTH_TOKEN"))
+ || (anthropic_key_raw.is_none()
+ && std::env::var("ANTHROPIC_API_KEY").is_err()
+ && std::env::var("ANTHROPIC_AUTH_TOKEN").is_ok());Also applies to: 2218-2229
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/config.rs` around lines 2078 - 2086, The current boolean
anthropic_is_auth_token only becomes true when no TOML key is present, so a TOML
anthropic_key that references env:ANTHROPIC_AUTH_TOKEN still selects x-api-key;
update the logic to also detect when toml.llm.anthropic_key explicitly
references the environment variable ANTHROPIC_AUTH_TOKEN (e.g., the raw string
contains or parses as "env:ANTHROPIC_AUTH_TOKEN" or resolve_env_value indicates
an env-ref) and treat that case as using auth token; modify the condition around
anthropic_is_auth_token (and the duplicate logic at the later block around the
2218-2229 occurrence) to check both the absence of a resolved TOML key and the
presence of an env reference to ANTHROPIC_AUTH_TOKEN before consulting
std::env::var.
| ) -> AnthropicRequest { | ||
| let is_oauth = auth::detect_auth_path(api_key) == AnthropicAuthPath::OAuthToken; | ||
| let auth_path = auth::detect_auth_path(api_key, is_auth_token); | ||
| let is_oauth = auth_path == AnthropicAuthPath::OAuthToken || auth_path == AnthropicAuthPath::AuthToken; |
There was a problem hiding this comment.
If AuthToken is meant to be “Bearer auth without Claude Code identity”, grouping it under is_oauth will also inject the Claude Code system preamble + tool-name normalization. I think is_oauth should stay strictly for the OAuth path.
| let is_oauth = auth_path == AnthropicAuthPath::OAuthToken || auth_path == AnthropicAuthPath::AuthToken; | |
| let is_oauth = auth_path == AnthropicAuthPath::OAuthToken; |
| let is_oauth = anthropic_request.auth_path == crate::llm::anthropic::AnthropicAuthPath::OAuthToken | ||
| || anthropic_request.auth_path == crate::llm::anthropic::AnthropicAuthPath::AuthToken; |
There was a problem hiding this comment.
AuthToken seems like it should behave like the plain API key path (no Claude Code identity/tool renames). Including it in is_oauth makes us reverse-map tool names even though we probably didn’t normalize them.
| let is_oauth = anthropic_request.auth_path == crate::llm::anthropic::AnthropicAuthPath::OAuthToken | |
| || anthropic_request.auth_path == crate::llm::anthropic::AnthropicAuthPath::AuthToken; | |
| let is_oauth = | |
| anthropic_request.auth_path == crate::llm::anthropic::AnthropicAuthPath::OAuthToken; |
| pub api_key: String, | ||
| pub name: Option<String>, | ||
| /// Whether the token came from ANTHROPIC_AUTH_TOKEN (uses Bearer auth) | ||
| pub is_auth_token: bool, |
There was a problem hiding this comment.
Nice to have the provenance tracked explicitly. One thing to watch when this lands on main: adding a new required field means every ProviderConfig { ... } literal needs to set it (most should be is_auth_token: false). Might be worth a quick rg 'ProviderConfig \{' sweep on main to avoid a surprise compile break during merge resolution.
Summary
This PR adds the missing piece from #135: proper handling of
ANTHROPIC_AUTH_TOKENto use Bearer authentication instead ofx-api-keyheader. This fixes 403 errors when using corporate Anthropic-compatible proxies.Also adds
ANTHROPIC_MODELenv var as requested by @pjv.Changes
Auth Header Fix
When
ANTHROPIC_AUTH_TOKENis used (detected by checking if the key came from that env var vsANTHROPIC_API_KEY), the request now uses:Authorization: Bearer <token>headerThis matches how Claude Code itself handles the distinction between API keys and auth tokens.
New Auth Path Variant
Added
AnthropicAuthPath::AuthTokenalongside existingApiKeyandOAuthToken:ApiKey→x-api-keyheader (native Anthropic)OAuthToken→Authorization: Bearer+ identity headers (Claude Code OAuth)AuthToken(new) →Authorization: Beareronly (proxy tokens)ANTHROPIC_MODEL Env Var
Sets all
anthropic/*routes at once. Example:This sets channel, branch, worker, compactor, and cortex all to
anthropic/claude-opus-4-6.Files Changed
src/llm/anthropic/auth.rs- NewAuthTokenvariant, updateddetect_auth_pathandapply_auth_headerssrc/config.rs-is_auth_tokentracking inProviderConfig,ANTHROPIC_MODELsupportsrc/llm/anthropic/params.rs- Threadis_auth_tokenthrough request buildingsrc/llm/model.rs- Passis_auth_tokenfrom provider configsrc/api/providers.rs,src/llm/manager.rs- Addis_auth_token: falseto test providersTesting
Added 3 new unit tests for
AuthToken:auth_token_uses_bearer_headerauth_token_has_no_identity_headersauth_token_has_streaming_beta_but_no_oauth_betaNotes
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFICwas requested but deferred as it requires more infrastructure workANTHROPIC_API_KEYusers are unaffectedFixes
ANTHROPIC_AUTH_TOKENNote
This change adds support for auth tokens via the
ANTHROPIC_AUTH_TOKENenvironment variable with proper Bearer authentication, and introduces theANTHROPIC_MODELenvironment variable to configure all Anthropic-based LLM process models in one place. The implementation detects auth token usage and automatically handles the appropriate authentication headers (Bearer without Claude Code identity), while maintaining backward compatibility with existing API key configuration.Written by Tembo for commit 5b9074e. This will update automatically on new commits.