{"record":{"id":"e0f351d41754c3c8","repo":"BerriAI/litellm","slug":"azure-ad-authentication-failed-for-redis","errorCode":null,"errorMessage":"Azure AD authentication failed for Redis","messagePattern":"Azure AD authentication failed for Redis","errorType":"exception","errorClass":"AuthenticationError","httpStatus":null,"severity":"error","filePath":"litellm/_redis.py","lineNumber":322,"sourceCode":"        # Only include username when explicitly set — sending AUTH \"\" <token>\n        # is invalid for most ACL-configured Azure Redis instances.\n        username: Final = os.environ.get(\"REDIS_USERNAME\", \"\")\n        if username:\n            auth_args = (username, access_token)\n        else:\n            auth_args = (access_token,)\n\n        self.send_command(\"AUTH\", *auth_args, check_health=False)\n\n        try:\n            auth_response = self.read_response()\n        except AuthenticationWrongNumberOfArgsError:\n            # Fallback: try with just the token (Redis < 6 / no ACL)\n            self.send_command(\"AUTH\", access_token, check_health=False)\n            auth_response = self.read_response()\n\n        if str_if_bytes(auth_response) != \"OK\":\n            raise AuthenticationError(\"Azure AD authentication failed for Redis\")\n\n    # Attach the live credential object so async paths can wrap it in\n    # AzureADCredentialProvider for refresh-aware token retrieval. The raw\n    # client_id/tenant_id/secret are intentionally NOT exposed here — the\n    # credential closure already holds them.\n    ad_connect._azure_credential = credential\n    return ad_connect\n\n\ndef get_redis_url_from_environment():\n    if \"REDIS_URL\" in os.environ:\n        return os.environ[\"REDIS_URL\"]\n\n    if \"REDIS_HOST\" not in os.environ or \"REDIS_PORT\" not in os.environ:\n        raise ValueError(\"Either 'REDIS_URL' or both 'REDIS_HOST' and 'REDIS_PORT' must be specified for Redis.\")\n\n    if \"REDIS_SSL\" in os.environ and os.environ[\"REDIS_SSL\"].lower() == \"true\":\n        redis_protocol = \"rediss\"","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/_redis.py#L304-L340","documentation":"For Azure Cache for Redis with Entra ID auth, litellm sends AUTH with an access token (with a fallback to single-arg AUTH for older Redis). If the server's reply is not 'OK', redis.AuthenticationError('Azure AD authentication failed for Redis') is raised: the token was rejected — wrong audience, unauthorized identity, or token acquisition issues.","triggerScenarios":"azure_redis_ad_token=true while AZURE_CLIENT_ID/TENANT_ID/CLIENT_SECRET (or ManagedIdentityCredential) produce a token that the cache rejects: identity lacks Redis ACL/Contributor permissions, token audience mismatch for the cache endpoint, or connecting with access keys auth configured on the cache while sending Entra tokens.","commonSituations":"Azure Cache with 'Entra ID authentication' enabled but the managed identity not added under Data access configuration; ClientSecretCredential with an expired/rotated secret in a long-running proxy; local dev with az login identity that has no Redis role; mixing key-based URL (password in REDIS_URL) with AAD path.","solutions":["In the Azure cache's Data Access (IAM) settings, add the connecting identity as Redis User/Contributor","Verify the credential: unset AZURE_CLIENT_SECRET to test DefaultAzureCredential/Managed Identity, or refresh the rotated secret","Ensure Entra authentication is actually enabled on the cache and you connect over TLS (port 6380) to the correct host","Remove any legacy password from the Redis URL/config so the AAD path is used consistently"],"exampleFix":"# before\nREDIS_HOST=mycache.redis.cache.windows.net\nREDIS_PORT=6380\nexport REDIS_AZURE_AD_TOKEN=true\n# identity not in cache ACL -> AuthenticationError: Azure AD authentication failed for Redis\n\n# after\naz redis access-policy-assignment create ...  # or Portal: Data access -> Add identity (Redis User)\n# redeploy proxy; AUTH now returns OK","handlingStrategy":"try-catch","validationCode":"from azure.identity import DefaultAzureCredential\n\ndef can_get_azure_token(scope: str) -> bool:\n    \"\"\"Pre-flight: can we even acquire an Entra token for the cache?\"\"\"\n    try:\n        DefaultAzureCredential().get_token(scope)\n        return True\n    except Exception:\n        return False\n\n# scope is typically \"https://<cache-name>.redis.cache.windows.net/.default\"","typeGuard":null,"tryCatchPattern":"from redis.exceptions import AuthenticationError\n\ntry:\n    cache = RedisCache(host=\"mycache.redis.cache.windows.net\", port=6380,\n                       azure_redis_ad_token=True, ssl=True)\n    cache.ping()\nexcept AuthenticationError as e:\n    if \"Azure AD\" in str(e):\n        raise RuntimeError(\n            \"Entra token rejected: add this identity as Redis User in the cache's \"\n            \"Data Access settings and verify AZURE_* credential env vars\"\n        ) from e\n    raise","preventionTips":["Add the connecting identity (managed identity or SP) under the cache's Data access configuration before enabling AAD","In IaC, declare the Redis access policy assignment alongside the cache so it can't drift","Monitor secret expiry if using ClientSecretCredential; prefer managed identity on Azure compute","Keep key-based auth out of the URL when using the AAD path to avoid mixed auth"],"tags":["redis","azure","entra-id","authentication","azure-cache","cache"],"backgroundTag":"authentication-failed","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}