mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-09 02:24:40 +00:00
fix(proxy): do not forward Authorization header to LLM provider when used for LiteLLM proxy auth
When forward_llm_provider_auth_headers=true, Authorization: Bearer <litellm-key> was being forwarded to Anthropic if it looked like an OAuth key, causing auth failures. Now checked against authenticated_with_header: if Authorization was used to authenticate with the proxy, it is always stripped before forwarding to the LLM provider. Made-with: Cursor
This commit is contained in:
@@ -283,7 +283,9 @@ def clean_headers(
|
||||
header_lower = header.lower()
|
||||
|
||||
if header_lower == "authorization" and is_anthropic_oauth_key(value):
|
||||
clean_headers[header] = value
|
||||
if authenticated_with_header is None or authenticated_with_header.lower() != "authorization":
|
||||
clean_headers[header] = value
|
||||
continue
|
||||
# Special handling for x-api-key: forward it based on authenticated_with_header
|
||||
elif header_lower == "x-api-key":
|
||||
if (
|
||||
|
||||
@@ -626,3 +626,74 @@ class TestProxyOAuthHeaderForwarding:
|
||||
# x-litellm-api-key should be excluded (special header)
|
||||
assert "x-litellm-api-key" not in cleaned
|
||||
assert cleaned["content-type"] == "application/json"
|
||||
|
||||
def test_clean_headers_authorization_not_forwarded_when_used_for_litellm_auth(
|
||||
self,
|
||||
):
|
||||
"""Authorization Bearer (LiteLLM key) must never be forwarded to the LLM provider.
|
||||
|
||||
When a user sends their LiteLLM key as 'Authorization: Bearer sk-1234' and
|
||||
forward_llm_provider_auth_headers=True, the Authorization header must be stripped
|
||||
— not sent to Anthropic as if it were an Anthropic API key.
|
||||
"""
|
||||
from starlette.datastructures import Headers
|
||||
|
||||
from litellm.proxy.litellm_pre_call_utils import clean_headers
|
||||
|
||||
raw_headers = Headers(
|
||||
raw=[
|
||||
(b"authorization", b"Bearer sk-1234-litellm-proxy-key"),
|
||||
(b"x-api-key", b"sk-ant-api03-real-anthropic-key"),
|
||||
(b"content-type", b"application/json"),
|
||||
]
|
||||
)
|
||||
# Authorization was the header used for LiteLLM auth
|
||||
cleaned = clean_headers(
|
||||
raw_headers,
|
||||
forward_llm_provider_auth_headers=True,
|
||||
authenticated_with_header="authorization",
|
||||
)
|
||||
|
||||
# Authorization must NOT be forwarded — it was used for proxy auth
|
||||
assert "authorization" not in cleaned
|
||||
assert "Authorization" not in cleaned
|
||||
# x-api-key should be forwarded (it's the real Anthropic key, auth was via Authorization)
|
||||
assert "x-api-key" in cleaned
|
||||
assert cleaned["x-api-key"] == "sk-ant-api03-real-anthropic-key"
|
||||
assert cleaned["content-type"] == "application/json"
|
||||
|
||||
def test_clean_headers_oauth_authorization_forwarded_when_not_used_for_litellm_auth(
|
||||
self,
|
||||
):
|
||||
"""OAuth Authorization header IS forwarded when x-litellm-api-key was used for proxy auth."""
|
||||
from unittest.mock import patch
|
||||
|
||||
from starlette.datastructures import Headers
|
||||
|
||||
from litellm.proxy.litellm_pre_call_utils import clean_headers
|
||||
|
||||
oauth_token = "Bearer claude-gODtUFO8RoSnClWTtHKFJg"
|
||||
|
||||
raw_headers = Headers(
|
||||
raw=[
|
||||
(b"x-litellm-api-key", b"sk-litellm-proxy-key"),
|
||||
(b"authorization", oauth_token.encode()),
|
||||
(b"content-type", b"application/json"),
|
||||
]
|
||||
)
|
||||
# x-litellm-api-key was used for LiteLLM auth; Authorization carries the Anthropic OAuth token
|
||||
with patch(
|
||||
"litellm.llms.anthropic.common_utils.is_anthropic_oauth_key",
|
||||
return_value=True,
|
||||
):
|
||||
cleaned = clean_headers(
|
||||
raw_headers,
|
||||
forward_llm_provider_auth_headers=True,
|
||||
authenticated_with_header="x-litellm-api-key",
|
||||
)
|
||||
|
||||
# OAuth Authorization should be forwarded (not used for proxy auth)
|
||||
assert "authorization" in cleaned
|
||||
assert cleaned["authorization"] == oauth_token
|
||||
# Proxy key must be stripped
|
||||
assert "x-litellm-api-key" not in cleaned
|
||||
|
||||
Reference in New Issue
Block a user