fix(azure): preserve AD token refresh in v1 OpenAI client path#28627
Conversation
The /openai/v1/ code path (api_version in {"v1", "latest", "preview"})
constructs a plain OpenAI/AsyncOpenAI client, but only forwarded
`api_key` from `azure_client_params`. When `enable_azure_ad_token_refresh`
is set (or any AD-only auth), `api_key` is None and the client
constructor raised "The api_key client option must be set...", breaking
every Azure call with a v1 api_version.
The OpenAI SDK (>=2.20.0) accepts a callable for `api_key` and re-invokes
it on every request via `_refresh_api_key`, so we now forward
`azure_ad_token_provider` directly — preserving the per-request token
refresh behavior of the regular AzureOpenAI client and avoiding the
expiry hole that resolving the token once at client-creation time would
introduce. Static `azure_ad_token` strings fall through to `api_key`.
For the async path we wrap the sync provider returned by azure-identity
in an async function since AsyncOpenAI expects `Callable[[], Awaitable[str]]`.
Fixes #27945
https://claude.ai/code/session_01UnzrDSFUUgp5T2wRoPMxq5
|
|
Greptile SummaryThis PR fixes Azure AD token refresh for the v1 API path (
Confidence Score: 3/5The auth-forwarding logic itself is sound, but the cache key uses The core fix correctly threads the AD token provider through to the OpenAI client and the async wrapping with litellm/llms/azure/common_utils.py — specifically the cache-key construction around line 464–471 where
|
| Filename | Overview |
|---|---|
| litellm/llms/azure/common_utils.py | Extends the v1 API path to forward Azure AD token providers as api_key, and extends the cache key to distinguish AD configs. The cache key uses id() of the callable provider, which is a memory address that Python can reuse after GC, creating a risk of cache aliasing between callers with different credentials. |
| tests/test_litellm/llms/azure/test_azure_common_utils.py | Adds six focused regression tests covering provider forwarding, token rotation, static AD token, api_key precedence, cache separation for distinct providers/credentials, and cache reuse for identical configs. All tests use mocks; no real network calls. |
Reviews (3): Last reviewed commit: "fix(azure): include AD credential identi..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
PR overviewAzure v1 AD token client handling updatedThis PR preserves Azure AD token providers on the OpenAI v1 client path and adds AD credential material into the Azure client cache key. I checked the surrounding client cache construction, Azure SDK initialization, and call sites and did not find a new attacker-reachable security issue. Security review
Risk: 2/10 |
|
The code path mentioned in the Greptile is not reachable. The OpenAI client stores the callable provider on |
|
nit: Code looks good. Can you add ss/video showing this works as expected? Thanks! |
End-to-end verification (before / after) — real Azure calls, no mockingReproduced the exact scenario this PR fixes: an Azure config that authenticates with an
Before the fix the v1 branch forwarded only Reproduction script and raw output captures: |
…AI#28627) * fix(azure): preserve AD token refresh in v1 OpenAI client path The /openai/v1/ code path (api_version in {"v1", "latest", "preview"}) constructs a plain OpenAI/AsyncOpenAI client, but only forwarded `api_key` from `azure_client_params`. When `enable_azure_ad_token_refresh` is set (or any AD-only auth), `api_key` is None and the client constructor raised "The api_key client option must be set...", breaking every Azure call with a v1 api_version. The OpenAI SDK (>=2.20.0) accepts a callable for `api_key` and re-invokes it on every request via `_refresh_api_key`, so we now forward `azure_ad_token_provider` directly — preserving the per-request token refresh behavior of the regular AzureOpenAI client and avoiding the expiry hole that resolving the token once at client-creation time would introduce. Static `azure_ad_token` strings fall through to `api_key`. For the async path we wrap the sync provider returned by azure-identity in an async function since AsyncOpenAI expects `Callable[[], Awaitable[str]]`. Fixes BerriAI#27945 https://claude.ai/code/session_01UnzrDSFUUgp5T2wRoPMxq5 * fix(azure): offload sync token provider to thread in v1 async wrapper * fix(azure): include AD credential identity in v1 client cache key --------- Co-authored-by: Claude <noreply@anthropic.com> (cherry picked from commit 96a2e8b)


Automated copy of #28625 into
litellm_internal_stagingfor pr-babysitter.Original head:
BerriAI/litellm:claude/busy-edison-90ZbL@abfdb72798a7Note
Medium Risk
Touches Azure authentication and client caching behavior; mistakes could break Azure v1 requests or accidentally reuse clients across different credentials, though changes are localized and test-covered.
Overview
Ensures the Azure v1 OpenAI client path forwards Azure AD auth by setting the
OpenAI/AsyncOpenAIapi_keytoapi_key || azure_ad_token_provider || azure_ad_token, preserving token refresh behavior when using a callable provider.For async usage, wraps sync Azure Identity token providers with an async
asyncio.to_threadwrapper to avoid blocking the event loop, and updates the in-memory client cache key to incorporate AD provider identity and hashed credential inputs (token, client secret, password) to prevent cross-credential client reuse. Adds regression tests covering provider forwarding, async token rotation, precedence rules, and cache separation/reuse.Reviewed by Cursor Bugbot for commit ca50412. Bugbot is set up for automated code reviews on this repo. Configure here.