BerriAI/litellm · critical · ValueError

audience must be provided unless disable_audience_validation

Error message

audience must be provided unless disable_audience_validation=True

What it means

ValueError raised in _build_decode_kwargs (litellm/proxy/auth/handle_jwt.py): JWT decoding options are being built with audience=None while disable_audience_validation is False. The guard makes disabling audience verification an explicit choice - a config that simply lacks an audience (e.g. a model validator was bypassed or a config was constructed programmatically) must not silently skip audience checks, since that would accept cross-tenant tokens from other applications sharing the IdP's signing keys.

Source

Thrown at litellm/proxy/auth/handle_jwt.py:917

        for key in ["kty", "kid", "n", "e", "x", "y", "crv"]:
            if key in public_key:
                jwk[key] = public_key[key]
        return jwk

    def _get_decode_options(
        self,
        audience: str | list[str] | None,
        issuer: str | None = None,
        disable_audience_validation: bool = False,
    ) -> dict | None:
        # Disabling audience verification must be an explicit choice — never
        # an implicit consequence of ``audience`` being None. Otherwise a
        # caller that accidentally constructs a config with ``audience=None``
        # (bypassing the model validator) would silently lose audience
        # validation. Require callers to opt in via
        # ``disable_audience_validation=True``.
        if audience is None and not disable_audience_validation:
            raise ValueError("audience must be provided unless disable_audience_validation=True")
        options: Final[dict] = {}
        if audience is None:
            options["verify_aud"] = False
        if issuer is None:
            options["verify_iss"] = False
        return options or None

    def _decode_jwt_with_public_key(
        self,
        token: str,
        public_key: dict | str,
        audience: str | list[str] | None,
        issuer: str | None = None,
        options: dict | None = None,
        disable_audience_validation: bool = False,
    ) -> dict:
        decode_options: Final = (
            options

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Set the audience: JWT_AUDIENCE env var or audience in litellm_jwtauth config, matching the aud claim your IdP mints (client_id or API identifier)
  2. If your tokens genuinely carry no aud claim, opt out explicitly with disable_audience_validation: true in litellm_jwtauth - and understand the cross-tenant acceptance risk
  3. Verify the token payload at jwt.io to see the exact aud value to configure

Example fix

# config.yaml - before
litellm_settings:
  litellm_jwtauth:
    jwt_public_key_url: https://idp.example.com/certs

# config.yaml - after
litellm_settings:
  litellm_jwtauth:
    jwt_public_key_url: https://idp.example.com/certs
    audience: https://api.example.com   # or: disable_audience_validation: true
Defensive patterns

Strategy: validation

Validate before calling

def validate_audience_config(audience, disable_audience_validation: bool) -> None:
    if audience is None and not disable_audience_validation:
        raise ValueError(
            "JWT auth config invalid: set 'audience' (matching the token's aud claim) "
            "or explicitly set disable_audience_validation=true"
        )

Prevention

When it happens

Trigger: JWT auth is active with no audience configured (no JWT_AUDIENCE / audience in litellm_jwtauth) and disable_audience_validation not set to true - e.g. after upgrading to a version that enforces this, or constructing litellm_jwtauth programmatically with audience=None.

Common situations: Older configs that never set an audience and relied on signature+expiry checks only; a version change turning the implicit skip into a hard error; code building JWTAuthManager settings directly with audience=None.

Related errors


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