PrefectHQ/fastmcp · error · IdentityAssertionError
OIDC discovery document for issuer {issuer!r} has no jwks_ur
Error message
OIDC discovery document for issuer {issuer!r} has no jwks_uri What it means
The discovery document is a JSON object but contains no usable `jwks_uri` string field, which FastMCP requires to fetch the issuer's signing keys. Without it no JWT verifier can be built, so validation fails with invalid_grant.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/identity_assertion.py:301
response = await client.get(config_url, timeout=10.0)
response.raise_for_status()
body = response.json()
except (httpx2.HTTPError, ValueError) as e:
self._discovery_failures[issuer] = time.monotonic()
raise IdentityAssertionError(
f"OIDC discovery for issuer {issuer!r} failed: {e}"
) from e
if not isinstance(body, dict):
# Valid JSON that isn't an object (e.g. `[]` or a bare string) —
# guard before .get() so a misbehaving discovery endpoint maps to
# invalid_grant, not a 500 on every subsequent exchange.
raise IdentityAssertionError(
f"OIDC discovery document for issuer {issuer!r} is not a JSON object"
)
jwks_uri = body.get("jwks_uri")
if not jwks_uri or not isinstance(jwks_uri, str):
raise IdentityAssertionError(
f"OIDC discovery document for issuer {issuer!r} has no jwks_uri"
)
return jwks_uri
async def _get_verifier(self, issuer: str) -> JWTVerifier:
from fastmcp.server.auth.providers.jwt import JWTVerifier as _JWTVerifier
verifier = self._verifiers.get(issuer)
if verifier is not None:
return verifier
jwks_uri = (self.config.jwks_uris or {}).get(issuer)
if not jwks_uri:
jwks_uri = await self._discover_jwks_uri(issuer)
algorithm = (self.config.algorithms or {}).get(issuer, self.config.algorithm)
verifier = _JWTVerifier(
jwks_uri=jwks_uri,View on GitHub (pinned to 1f02114297)
Solutions
- Fix the IdP metadata to include a valid string jwks_uri pointing at the JWKS endpoint (verify with curl).
- Verify with curl .../.well-known/openid-configuration | jq .jwks_uri that it returns a non-empty string URL.
- If the IdP cannot publish jwks_uri, configure FastMCP's JWT verifier with the JWKS URI explicitly rather than relying on discovery.
- Ensure the issuer URL in trusted_issuers points at the real OIDC provider, not a different server that happens to serve some JSON.
Example fix
// before
{"issuer": "https://idp.example.com"}
// after
{"issuer": "https://idp.example.com", "jwks_uri": "https://idp.example.com/.well-known/jwks.json"} Defensive patterns
Strategy: validation
Validate before calling
doc = httpx.get(issuer + '/.well-known/openid-configuration').json()
jwks_uri = doc.get('jwks_uri')
assert isinstance(jwks_uri, str) and jwks_uri.startswith('https://') Type guard
def has_jwks_uri(doc: dict) -> bool:
u = doc.get('jwks_uri')
return isinstance(u, str) and bool(u) Try / catch
try:
await provider.validate(assertion)
except IdentityAssertionError as e:
if 'no jwks_uri' in str(e):
log.error('IdP metadata missing jwks_uri; configure explicit JWKS')
raise Prevention
- Confirm jwks_uri is present in IdP metadata before onboarding an issuer
- Prefer explicit JWKS configuration for minimal OIDC implementations
- Test the JWKS URL is reachable, not just present
- Keep IdP metadata endpoints standard and complete
When it happens
Trigger: validate() on an assertion whose issuer's discovery document has jwks_uri missing, empty, null, or a non-string JSON type (number/list/object).
Common situations: Minimal/broken OIDC implementations that omit jwks_uri from metadata; IdPs where JWKS is served at a nonstandard location and metadata was never configured; partially deployed IdP staging environments.
Related errors
- Missing required configuration metadata: {attr}
- OIDC discovery for issuer {issuer!r} recently failed; backin
- OIDC discovery for issuer {issuer!r} failed: {e}
- OIDC discovery document for issuer {issuer!r} is not a JSON
- Invalid URL for configuration metadata: {attr}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/51692ab7a5f428ad.
Report an issue: GitHub.