{"record":{"id":"5bc6d907e27ae8af","repo":"BerriAI/litellm","slug":"audience-must-be-provided-unless-disable-audience","errorCode":null,"errorMessage":"audience must be provided unless disable_audience_validation=True","messagePattern":"audience must be provided unless disable_audience_validation=True","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"critical","filePath":"litellm/proxy/auth/handle_jwt.py","lineNumber":917,"sourceCode":"        for key in [\"kty\", \"kid\", \"n\", \"e\", \"x\", \"y\", \"crv\"]:\n            if key in public_key:\n                jwk[key] = public_key[key]\n        return jwk\n\n    def _get_decode_options(\n        self,\n        audience: str | list[str] | None,\n        issuer: str | None = None,\n        disable_audience_validation: bool = False,\n    ) -> dict | None:\n        # Disabling audience verification must be an explicit choice — never\n        # an implicit consequence of ``audience`` being None. Otherwise a\n        # caller that accidentally constructs a config with ``audience=None``\n        # (bypassing the model validator) would silently lose audience\n        # validation. Require callers to opt in via\n        # ``disable_audience_validation=True``.\n        if audience is None and not disable_audience_validation:\n            raise ValueError(\"audience must be provided unless disable_audience_validation=True\")\n        options: Final[dict] = {}\n        if audience is None:\n            options[\"verify_aud\"] = False\n        if issuer is None:\n            options[\"verify_iss\"] = False\n        return options or None\n\n    def _decode_jwt_with_public_key(\n        self,\n        token: str,\n        public_key: dict | str,\n        audience: str | list[str] | None,\n        issuer: str | None = None,\n        options: dict | None = None,\n        disable_audience_validation: bool = False,\n    ) -> dict:\n        decode_options: Final = (\n            options","sourceCodeStart":899,"sourceCodeEnd":935,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/auth/handle_jwt.py#L899-L935","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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)","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","Verify the token payload at jwt.io to see the exact aud value to configure"],"exampleFix":"# config.yaml - before\nlitellm_settings:\n  litellm_jwtauth:\n    jwt_public_key_url: https://idp.example.com/certs\n\n# config.yaml - after\nlitellm_settings:\n  litellm_jwtauth:\n    jwt_public_key_url: https://idp.example.com/certs\n    audience: https://api.example.com   # or: disable_audience_validation: true","handlingStrategy":"validation","validationCode":"def validate_audience_config(audience, disable_audience_validation: bool) -> None:\n    if audience is None and not disable_audience_validation:\n        raise ValueError(\n            \"JWT auth config invalid: set 'audience' (matching the token's aud claim) \"\n            \"or explicitly set disable_audience_validation=true\"\n        )","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always configure audience when the IdP mints an aud claim - decode a sample token to read it","Treat disable_audience_validation as a documented security exception, never a default","Add a config lint step that rejects JWT auth configs lacking both audience and the explicit opt-out"],"tags":["jwt","audience","validation","configuration","security","authentication"],"backgroundTag":"jwt-audience-validation","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}