feat: support Anthropic OAuth tokens in passthrough endpoint#20429
feat: support Anthropic OAuth tokens in passthrough endpoint#20429klaudworks wants to merge 2 commits intoBerriAI:mainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
a898372 to
f55aaf2
Compare
f55aaf2 to
af9db43
Compare
af9db43 to
953a974
Compare
The passthrough endpoint was broken in several ways: 1. Client x-api-key was overwritten by server credentials 2. Client Authorization header (OAuth) was overwritten 3. If server had no ANTHROPIC_API_KEY configured, it sent 'None' as the key 4. x-litellm-api-key was leaked to upstream providers Now uses correct priority: 1. Client x-api-key -> forward as-is 2. Client Authorization -> forward as-is 3. No client auth -> use server credentials (if configured) 4. Nothing -> forward without credentials (let Anthropic return auth error) Also fixes security issue where x-litellm-api-key was forwarded to providers.
953a974 to
0a36521
Compare
Greptile OverviewGreptile SummaryFixed Anthropic passthrough endpoint to respect client-provided credentials instead of always overwriting with server credentials. Also fixed security issue where Key Changes:
Issues Found:
Confidence Score: 3/5
|
| Filename | Overview |
|---|---|
| litellm/passthrough/utils.py | Added x-litellm-api-key to list of headers that should not be forwarded to upstream providers (security fix) |
| litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py | Modified anthropic_proxy_route to respect client-provided credentials instead of always overwriting with server credentials. Logic doesn't specifically detect OAuth tokens as PR description claims. |
| tests/test_litellm/proxy/pass_through_endpoints/test_passthrough_endpoints_common_utils.py | Added unit tests for header forwarding behavior, verifying x-litellm-api-key is stripped and other headers are preserved |
Sequence Diagram
sequenceDiagram
participant Client
participant Proxy as LiteLLM Proxy
participant Route as anthropic_proxy_route
participant PassThrough as pass_through_request
participant Utils as HttpPassThroughEndpointHelpers
participant Anthropic as Anthropic API
Client->>Proxy: POST /anthropic/v1/messages
Note over Client,Proxy: With auth headers or without
Proxy->>Route: Handle request
alt Client provides auth header
Route->>Route: Set custom_headers = empty dict
Note over Route: Forward client credentials as-is
else No client credentials
Route->>Route: Get server credentials
alt Server has credentials
Route->>Route: Set custom_headers with server credentials
else No server credentials
Route->>Route: Set custom_headers = empty dict
end
end
Route->>PassThrough: create_pass_through_route(custom_headers, _forward_headers=True)
PassThrough->>Utils: forward_headers_from_request()
Utils->>Utils: Strip: content-length, host, x-litellm-api-key
Utils->>Utils: Merge request_headers with custom_headers
Utils->>Utils: Process x-pass-* prefixed headers
Utils-->>PassThrough: Final headers
PassThrough->>Anthropic: Forward request with final headers
Anthropic-->>PassThrough: Response
PassThrough-->>Client: Return response
| x_api_key_header = request.headers.get("x-api-key", "") | ||
| auth_header = request.headers.get("authorization", "") | ||
|
|
||
| if x_api_key_header or auth_header: | ||
| custom_headers = {} | ||
| else: | ||
| anthropic_api_key = passthrough_endpoint_router.get_credentials( | ||
| custom_llm_provider="anthropic", | ||
| region_name=None, | ||
| ) | ||
| if anthropic_api_key: | ||
| custom_headers = {"x-api-key": anthropic_api_key} | ||
| else: | ||
| custom_headers = {} |
There was a problem hiding this comment.
PR description claims this detects OAuth tokens (pattern: Bearer sk-ant-oat...), but the code doesn't check for OAuth tokens specifically. It checks if ANY x-api-key or authorization header exists, which means all client credentials bypass server credentials. If you specifically want OAuth detection as described, consider checking for the OAuth token pattern.
Prompt To Fix With AI
This is a comment left during a code review.
Path: litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py
Line: 596:609
Comment:
PR description claims this detects OAuth tokens (pattern: `Bearer sk-ant-oat...`), but the code doesn't check for OAuth tokens specifically. It checks if ANY `x-api-key` or `authorization` header exists, which means all client credentials bypass server credentials. If you specifically want OAuth detection as described, consider checking for the OAuth token pattern.
How can I resolve this? If you propose a fix, please make it concise.| if x_api_key_header or auth_header: | ||
| custom_headers = {} | ||
| else: | ||
| anthropic_api_key = passthrough_endpoint_router.get_credentials( | ||
| custom_llm_provider="anthropic", | ||
| region_name=None, | ||
| ) | ||
| if anthropic_api_key: | ||
| custom_headers = {"x-api-key": anthropic_api_key} | ||
| else: | ||
| custom_headers = {} |
There was a problem hiding this comment.
Nested if-else creates empty dict in multiple paths. Consider simplifying with ternary operator for the inner condition.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix With AI
This is a comment left during a code review.
Path: litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py
Line: 599:609
Comment:
Nested if-else creates empty dict in multiple paths. Consider simplifying with ternary operator for the inner condition.
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise.
Additional Comments (1)
Prompt To Fix With AIThis is a comment left during a code review.
Path: tests/test_litellm/proxy/pass_through_endpoints/test_passthrough_endpoints_common_utils.py
Line: 98:142
Comment:
Tests only verify header stripping logic but don't test the new OAuth/credential priority logic in `anthropic_proxy_route`. Add integration tests that verify:
- Client headers are forwarded instead of server credentials
- Server credentials are used when client provides neither
How can I resolve this? If you propose a fix, please make it concise. |
Client-provided credentials now take precedence over server credentials in the /anthropic/ passthrough endpoint. This enables mixed mode where: 1. Client sends x-api-key → forwarded as-is (user pays via own API key) 2. Client sends Authorization → forwarded as-is (user pays via OAuth/Max) 3. No client credentials + server ANTHROPIC_API_KEY → server key used 4. No client credentials + no server key → no credentials forwarded Previously the server always sent x-api-key (even literal "None" when unconfigured), overwriting any client-provided credentials and breaking Claude Code Max (OAuth) and BYOK scenarios. Supersedes the simpler one-liner from d742c76 on v1.81.12-stable-patched. Based on the approach from PR BerriAI#20429 (closed) and reverted PR BerriAI#14821.
Summary
Enables Anthropic OAuth token authentication (used by Claude Code / Claude Max) through the
/anthropic/{endpoint:path}passthrough endpoint.Problem
When users authenticate with Claude Max OAuth tokens (
sk-ant-oat...), the passthrough endpoint was overwriting theAuthorizationheader with the server'sx-api-key, causing authentication failures.Solution
Authorizationheader starts withBearer sk-ant-oatx-api-key)ANTHROPIC_API_KEYas beforex-pass-*prefix in both casesChanges
litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py: Add OAuth detection logictests/pass_through_unit_tests/test_anthropic_passthrough_oauth.py: Add unit testsTesting