BerriAI/litellm · error · Exception
JWT Auth: OIDC discovery endpoint {url} returned status {res
Error message
JWT Auth: OIDC discovery endpoint {url} returned status {response.status_code}: {response.text} What it means
Raised in JWTAuthBase._resolve_jwks_url (litellm/proxy/auth/handle_jwt.py). When JWT_PUBLIC_KEY_URL points at an OIDC discovery document (URL containing .well-known/openid-configuration), the proxy fetches it to find jwks_uri; if the endpoint answers with any non-200 status, this exception aborts JWT auth. The resolved jwks_uri is cached, so this fires on the first uncached lookup.
Source
Thrown at litellm/proxy/auth/handle_jwt.py:622
async def _resolve_jwks_url(self, url: str) -> str:
"""
If url points to an OIDC discovery document (*.well-known/openid-configuration),
fetch it and return the jwks_uri contained within. Otherwise return url unchanged.
This lets JWT_PUBLIC_KEY_URL be set to a well-known discovery endpoint instead of
requiring operators to manually find the JWKS URL.
"""
if ".well-known/openid-configuration" not in url:
return url
cache_key: Final = f"litellm_oidc_discovery_{url}"
cached_jwks_uri: Final = await self.user_api_key_cache.async_get_cache(cache_key)
if cached_jwks_uri is not None:
return cached_jwks_uri
verbose_proxy_logger.debug("JWT Auth: Fetching OIDC discovery document from %s", url)
response: Final = await self.http_handler.get(url)
if response.status_code != 200:
raise Exception(
f"JWT Auth: OIDC discovery endpoint {url} returned status {response.status_code}: {response.text}"
)
try:
discovery: Final = response.json()
except Exception as e:
raise Exception(f"JWT Auth: Failed to parse OIDC discovery document at {url}: {e}")
jwks_uri: Final = discovery.get("jwks_uri")
if not jwks_uri:
raise Exception(f"JWT Auth: OIDC discovery document at {url} does not contain a 'jwks_uri' field.")
verbose_proxy_logger.debug("JWT Auth: Resolved OIDC discovery %s -> jwks_uri=%s", url, jwks_uri)
await self.user_api_key_cache.async_set_cache(
key=cache_key,
value=jwks_uri,
ttl=self._get_public_key_cache_ttl(),
)
return jwks_uriView on GitHub (pinned to 77b7c6c40c)
Solutions
- curl the exact discovery URL from the proxy host and confirm it returns 200 with JSON containing jwks_uri
- Fix the tenant/realm path (e.g. Keycloak: /realms/<realm>/.well-known/openid-configuration; Auth0: correct domain)
- Bypass discovery entirely: set JWT_PUBLIC_KEY_URL to the JWKS URL itself (the literal keys endpoint), which skips this fetch
- If the failure was a transient 5xx, it will be retried on the next auth attempt once the IdP recovers - check IdP status
Example fix
# before: discovery URL that 404s (wrong realm) JWT_PUBLIC_KEY_URL=https://keycloak.example.com/realms/wrong-realm/.well-known/openid-configuration # after: point directly at the JWKS endpoint (no discovery step) JWT_PUBLIC_KEY_URL=https://keycloak.example.com/realms/my-realm/protocol/openid-connect/certs
Defensive patterns
Strategy: validation
Validate before calling
import httpx, os
async def assert_discovery_reachable() -> None:
url = os.environ["JWT_PUBLIC_KEY_URL"]
if ".well-known/openid-configuration" not in url:
return # plain JWKS URL, discovery step skipped
async with httpx.AsyncClient() as c:
r = await c.get(url)
r.raise_for_status()
assert "jwks_uri" in r.json(), "discovery document missing jwks_uri" Prevention
- Add a startup/canary check that curls the discovery URL from the proxy host
- Prefer pointing JWT_PUBLIC_KEY_URL directly at the JWKS endpoint to remove the discovery dependency
- Double-check realm/tenant path segments (Keycloak realms, Auth0 domains) when copying IdP URLs
When it happens
Trigger: JWT_PUBLIC_KEY_URL=https://idp.example.com/.well-known/openid-configuration and the IdP returns 404 (wrong path/tenant), 401/403 (discovery behind auth), or 5xx (IdP error) when the proxy fetches it during key resolution.
Common situations: Wrong tenant/region segment in the discovery URL (common with Keycloak realms and Auth0 domains); transient IdP outage at startup or during cache expiry; the discovery endpoint requires credentials; a corporate proxy returning 407/502.
Related errors
- JWT Auth: OIDC discovery document at {url} does not contain
- JWT Auth: Failed to parse OIDC discovery document at {url}:
- MCPJWTSigner: access_token_discovery_uri discovery document
- Error parsing response: {e}. Check server logs for original
- No matching public key found. keys={resolved_jwks_url}, kid=
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/1deac8f9b272f11b.
Report an issue: GitHub.