refactor(proxy/auth): cherry-pick #29343 into patch/v1.87.0rc2 - #29365
Conversation
…9343) * refactor(proxy/auth): normalize Bearer prefix in safe-hash helper UserAPIKeyAuth._safe_hash_litellm_api_key now strips a leading "Bearer "/"bearer " prefix before its existing sk-/JWT classification, so the helper produces the same hashed output regardless of whether the caller stripped the Authorization header prefix or passed the header value through unchanged. * refactor(proxy/auth): make Bearer-prefix strip case-insensitive Per RFC 7235 the HTTP authorization scheme token is case-insensitive. Replace the two-prefix loop with a single case-insensitive check so the helper normalizes "Bearer ", "bearer ", "BEARER ", and any mixed-case variant before classifying the remainder as sk- or JWT. The contract test gains coverage of "BEARER " and "BeArEr ". * test(mcp): align auth-handler test expectations with safe-hash helper The two MCP auth tests asserted that UserAPIKeyAuth(api_key="Bearer ...") retained the raw header bytes on the api_key field. _safe_hash_litellm_api_key now normalizes that input — stripping the Bearer prefix and hashing the resulting sk- key — so the expectations move to the normalized form: the bare token in the parametrize case, and hash_token("sk-...") in the backward-compat assertion. This matches what the real auth flow produces (the builder strips Bearer and the DB stores the hashed token), so the mocks now line up with production rather than with the un-normalized validator output.
Greptile SummaryThis cherry-pick onto
Confidence Score: 5/5Safe to merge — the change is a small, well-scoped fix with no backwards-incompatible surface changes and is covered by a new contract test plus updated MCP auth tests. The three-file cherry-pick touches only the No files require special attention.
|
| Filename | Overview |
|---|---|
| litellm/proxy/_types.py | Adds case-insensitive Bearer prefix stripping in _safe_hash_litellm_api_key before sk-/JWT classification, fixing raw Bearer sk-... leaking into observability labels |
| tests/test_litellm/proxy/_experimental/mcp_server/auth/test_user_api_key_auth_mcp.py | Two existing assertions updated to reflect correct post-fix behavior: expected API key now properly excludes Bearer prefix, and sk- key assertion now expects a hash instead of the raw Bearer string |
| tests/test_litellm/proxy/test_proxy_types.py | New contract test verifying all four Bearer casing variants (Bearer, bearer, BEARER, BeArEr) produce the same hashed api_key/token as a bare sk- key |
Reviews (1): Last reviewed commit: "refactor(proxy/auth): normalize Bearer p..." | Re-trigger Greptile
Relevant issues
Cherry-pick of #29343 (merge commit
94a043efb2) onto thepatch/v1.87.0rc2branch (= tagv1.87.0-rc.2). Supersedes #29362, which targeted the olderpatch/v1.87.0rc1base.Linear ticket
n/a
Pre-Submission checklist
make test-unit(asserted in refactor(proxy/auth): normalize Bearer prefix in safe-hash helper #29343; this PR is a verbatim cherry-pick of the function body — see verification below)CI (LiteLLM team)
Bug verification on v1.87.0-rc.2
Confirmed the bug is still present at the v1.87.0-rc.2 tag (head of
patch/v1.87.0rc2) before this cherry-pick lands. rc.2 = rc.1 + 2 patch commits, neither of which touched_types.py, so the rc.1 verification carries over unchanged.Any caller that passes the raw
Authorizationheader value (Bearer sk-...) falls through toreturn api_keyunchanged, so observability labels (e.g. Prometheuslitellm_proxy_failed_requests_metric_total{hashed_api_key=...}) leak the literalBearer sk-...string instead of the sha256 hash.After this cherry-pick lands, the function body matches the source merge commit byte-for-byte — a case-insensitive
Bearerstrip runs before the existing sk-/JWT classification.Screenshots / Proof of Fix
End-to-end proof-of-fix (curl-driven Prometheus scrape showing the metric row going from
hashed_api_key="Bearer sk-..."to a proper sha256 hash) is captured in the original PR body at #29343 and was run against a live proxy with prometheus enabled. The cherry-pick is verbatim, so the same harness output applies.Type
Refactoring + Test
Changes
Verbatim cherry-pick of #29343's merge commit
94a043efb226c5ccdbfc028fbb930ce45fb965ebontopatch/v1.87.0rc2. Auto-merged cleanly (no conflicts). 3 files, +30/-7 — matches the sum of the three original commits exactly (+8/-5 in_types.py, +4/-2 in the MCP auth test, +18/-0 for the new contract test). The_safe_hash_litellm_api_keybody on this branch is byte-identical to the merge commit's version. Full rationale lives in the #29343 PR body.