BerriAI/litellm · error · AuthenticationError

Azure AD authentication failed for Redis

Error message

Azure AD authentication failed for Redis

What it means

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.

Solutions

  1. In the Azure cache's Data Access (IAM) settings, add the connecting identity as Redis User/Contributor
  2. Verify the credential: unset AZURE_CLIENT_SECRET to test DefaultAzureCredential/Managed Identity, or refresh the rotated secret
  3. Ensure Entra authentication is actually enabled on the cache and you connect over TLS (port 6380) to the correct host
  4. Remove any legacy password from the Redis URL/config so the AAD path is used consistently

Example fix

# before
REDIS_HOST=mycache.redis.cache.windows.net
REDIS_PORT=6380
export REDIS_AZURE_AD_TOKEN=true
# identity not in cache ACL -> AuthenticationError: Azure AD authentication failed for Redis

# after
az redis access-policy-assignment create ...  # or Portal: Data access -> Add identity (Redis User)
# redeploy proxy; AUTH now returns OK
Defensive patterns

Strategy: try-catch

Validate before calling

from azure.identity import DefaultAzureCredential

def can_get_azure_token(scope: str) -> bool:
    """Pre-flight: can we even acquire an Entra token for the cache?"""
    try:
        DefaultAzureCredential().get_token(scope)
        return True
    except Exception:
        return False

# scope is typically "https://<cache-name>.redis.cache.windows.net/.default"

Try / catch

from redis.exceptions import AuthenticationError

try:
    cache = RedisCache(host="mycache.redis.cache.windows.net", port=6380,
                       azure_redis_ad_token=True, ssl=True)
    cache.ping()
except AuthenticationError as e:
    if "Azure AD" in str(e):
        raise RuntimeError(
            "Entra token rejected: add this identity as Redis User in the cache's "
            "Data Access settings and verify AZURE_* credential env vars"
        ) from e
    raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/e0f351d41754c3c8. Report an issue: GitHub.

Appendix: source

Thrown at litellm/_redis.py:322

        # Only include username when explicitly set — sending AUTH "" <token>
        # is invalid for most ACL-configured Azure Redis instances.
        username: Final = os.environ.get("REDIS_USERNAME", "")
        if username:
            auth_args = (username, access_token)
        else:
            auth_args = (access_token,)

        self.send_command("AUTH", *auth_args, check_health=False)

        try:
            auth_response = self.read_response()
        except AuthenticationWrongNumberOfArgsError:
            # Fallback: try with just the token (Redis < 6 / no ACL)
            self.send_command("AUTH", access_token, check_health=False)
            auth_response = self.read_response()

        if str_if_bytes(auth_response) != "OK":
            raise AuthenticationError("Azure AD authentication failed for Redis")

    # Attach the live credential object so async paths can wrap it in
    # AzureADCredentialProvider for refresh-aware token retrieval. The raw
    # client_id/tenant_id/secret are intentionally NOT exposed here — the
    # credential closure already holds them.
    ad_connect._azure_credential = credential
    return ad_connect


def get_redis_url_from_environment():
    if "REDIS_URL" in os.environ:
        return os.environ["REDIS_URL"]

    if "REDIS_HOST" not in os.environ or "REDIS_PORT" not in os.environ:
        raise ValueError("Either 'REDIS_URL' or both 'REDIS_HOST' and 'REDIS_PORT' must be specified for Redis.")

    if "REDIS_SSL" in os.environ and os.environ["REDIS_SSL"].lower() == "true":
        redis_protocol = "rediss"

View on GitHub (pinned to 77b7c6c40c)