PrefectHQ/fastmcp · error · ValueError

JWKS URI not configured

Error message

JWKS URI not configured

What it means

This error means the JWT verification provider was asked to verify a token but its JWKS URI — the URL of the identity provider's JSON Web Key Set — was never set. The library throws it from _get_jwks_key because without a JWKS URI there is no way to fetch the public key needed to verify the token's signature. It is a configuration error in the provider, not a token problem.

Source

Thrown at fastmcp_slim/fastmcp/server/auth/providers/jwt.py:348

    async def _get_verification_key(self, token: str) -> str | bytes:
        """Get the verification key for the token."""
        if self.public_key:
            return self.public_key

        # Extract kid from token header for JWKS lookup
        try:
            header = decode_jwt_header(token)
            kid = header.get("kid")
            return await self._get_jwks_key(kid)

        except (ValueError, KeyError, IndexError, json.JSONDecodeError) as e:
            raise ValueError(f"Failed to extract key ID from token: {e}") from e

    async def _get_jwks_key(self, kid: str | None) -> str:
        """Fetch key from JWKS with simple caching and SSRF protection."""
        if not self.jwks_uri:
            raise ValueError("JWKS URI not configured")

        current_time = time.time()

        # Check cache first
        if current_time - self._jwks_cache_time < self._cache_ttl:
            if kid and kid in self._jwks_cache:
                return self._jwks_cache[kid]
            elif not kid and len(self._jwks_cache) == 1:
                # If no kid but only one key cached, use it
                return next(iter(self._jwks_cache.values()))

        # Fetch JWKS — with SSRF protection when enabled (untrusted URIs)
        try:
            jwks_data = await self._fetch_jwks()

            # Cache all usable keys. A key that cannot be converted is skipped
            # rather than failing the whole set — per RFC 7517 §5, clients
            # should ignore JWKs they don't understand. Otherwise one exotic

View on GitHub (pinned to 1f02114297)

Solutions

  1. Set jwks_uri in the verifier config to your identity provider's JWKS endpoint (e.g. https://idp.example.com/.well-known/jwks.json or the /.well-known/openid-configuration jwks_uri value)
  2. Verify the config source: if jwks_uri comes from an env var or settings file, confirm it is populated and non-empty at startup
  3. If you intend asymmetric verification, either provide jwks_uri or a static public_key/secret_key — one of them must be configured
  4. Add a startup validation that instantiates the verifier and checks jwks_uri before the server accepts traffic

Example fix

// before
verifier = JWTVerifier(issuer="https://idp.example.com")
// after
verifier = JWTVerifier(
    issuer="https://idp.example.com",
    jwks_uri="https://idp.example.com/.well-known/jwks.json",
)
Defensive patterns

Strategy: validation

Validate before calling

if not getattr(verifier, "jwks_uri", None):
    raise RuntimeError("JWTVerifier requires a jwks_uri for asymmetric verification")

Type guard

def has_jwks_uri(v) -> bool:
    return bool(getattr(v, "jwks_uri", None))

Try / catch

try:
    claims = await verifier.verify_token(token)
except ValueError as e:
    if "JWKS URI not configured" in str(e):
        # misconfiguration: fix server config, do not retry
        raise RuntimeError("JWT verifier misconfigured: set jwks_uri") from e
    raise

Prevention

When it happens

Trigger: Calling verify_token (via _get_verification_key -> _get_jwks_key) on a JWTVerifier/TokenVerifier instance constructed without a jwks_uri, or where the jwks_uri argument was None/empty string.

Common situations: Constructing the verifier programmatically and omitting jwks_uri while also omitting secret_key/public_key; env-driven config where the JWKS variable is unset or empty; copying a verifier config that only specified an issuer; switching from a static-key verifier to a JWKS verifier without moving the URL over.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/75dc659e6221cfe4. Report an issue: GitHub.