{"record":{"id":"23475fc5e4c7034e","repo":"BerriAI/litellm","slug":"azure-ad-token-access-token-not-returned","errorCode":null,"errorMessage":"Azure AD Token access_token not returned","messagePattern":"Azure AD Token access_token not returned","errorType":"http","errorClass":"AzureOpenAIError","httpStatus":422,"severity":"error","filePath":"litellm/llms/azure/common_utils.py","lineNumber":245,"sourceCode":"            \"grant_type\": \"client_credentials\",\n            \"scope\": scope,\n            \"client_assertion_type\": \"urn:ietf:params:oauth:client-assertion-type:jwt-bearer\",\n            \"client_assertion\": oidc_token,\n        },\n    )\n\n    if req_token.status_code != 200:\n        raise AzureOpenAIError(\n            status_code=req_token.status_code,\n            message=req_token.text,\n        )\n\n    azure_ad_token_json: Final[_AzureAdTokenJson] = req_token.json()\n    azure_ad_token_access_token = azure_ad_token_json.get(\"access_token\", None)\n    azure_ad_token_expires_in: Final = azure_ad_token_json.get(\"expires_in\", None)\n\n    if azure_ad_token_access_token is None:\n        raise AzureOpenAIError(status_code=422, message=\"Azure AD Token access_token not returned\")\n\n    if azure_ad_token_expires_in is None:\n        raise AzureOpenAIError(status_code=422, message=\"Azure AD Token expires_in not returned\")\n\n    azure_ad_cache.set_cache(\n        key=azure_ad_token_cache_key,\n        value=azure_ad_token_access_token,\n        ttl=azure_ad_token_expires_in,\n    )\n\n    return azure_ad_token_access_token\n\n\ndef select_azure_base_url_or_endpoint(azure_client_params: dict):\n    azure_endpoint: Final = azure_client_params.get(\"azure_endpoint\", None)\n    if azure_endpoint is not None:\n        # see : https://github.com/openai/openai-python/blob/3d61ed42aba652b547029095a7eb269ad4e1e957/src/openai/lib/azure.py#L192\n        if \"/openai/deployments\" in azure_endpoint:","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/azure/common_utils.py#L227-L263","documentation":"The token endpoint returned HTTP 200 but the JSON body had no access_token field. LiteLLM treats this as a 422 protocol violation because a successful client-credentials response must contain access_token per the OAuth 2.0 spec. It almost always means a non-Azure endpoint or a proxy answered 200 with a different payload.","triggerScenarios":"AZURE_AUTHORITY_HOST pointing at a service that returns 200 with HTML/JSON lacking access_token (a corporate proxy's captive portal, a misconfigured gateway); an API-management wrapper in front of the authority; a mocked test server returning an incomplete fixture.","commonSituations":"SSL-inspecting proxies rewriting the token response; typos in AZURE_AUTHORITY_HOST that hit a benign web server; test fixtures with only expires_in; adal/MSAL middleware in the path.","solutions":["Print/inspect the actual response your environment gets: curl -sv $AZURE_AUTHORITY_HOST/$AZURE_TENANT_ID/oauth2/v2.0/token to see what is answering.","Fix AZURE_AUTHORITY_HOST to the real authority (default https://login.microsoftonline.com or the sovereign equivalent).","Bypass corporate proxies/SSL inspection for login.microsoftonline.com (add to NO_PROXY or proxy allowlist).","In tests, make the mocked endpoint return both access_token and expires_in."],"exampleFix":"# before (mock returns incomplete body)\n{ \"token_type\": \"Bearer\", \"expires_in\": 3599 }\n\n# after\n{ \"token_type\": \"Bearer\", \"expires_in\": 3599, \"access_token\": \"eyJ...\" }","handlingStrategy":"validation","validationCode":"import os\n\ndef sane_authority() -> None:\n    host = os.getenv(\"AZURE_AUTHORITY_HOST\", \"https://login.microsoftonline.com\")\n    if \"login.microsoftonline\" not in host and \"login.microsoftonline.us\" not in host and \"login.chinacloudapi\" not in host:\n        raise ConfigError(f\"Suspicious AZURE_AUTHORITY_HOST: {host}\")","typeGuard":null,"tryCatchPattern":"try:\n    resp = litellm.completion(..., azure_ad_token=oidc)\nexcept AzureOpenAIError as e:\n    if e.status_code == 422 and \"access_token not returned\" in str(e):\n        log.error(\"token endpoint answered 200 without access_token — check AZURE_AUTHORITY_HOST/proxy\")\n    raise","preventionTips":["curl the authority endpoint once in deployment smoke tests and assert access_token in the JSON.","Do not put token endpoints behind rewriting proxies.","Mock servers must return spec-compliant token responses in tests."],"tags":["azure","oauth2","protocol","proxy"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}