{"record":{"id":"5287f19e9f549513","repo":"PrefectHQ/fastmcp","slug":"key-id-kid-found-in-jwks-but-its-key-type-is-u","errorCode":null,"errorMessage":"Key ID '{kid}' found in JWKS but its key type is unsupported","messagePattern":"Key ID '(.+?)' found in JWKS but its key type is unsupported","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/auth/providers/jwt.py","lineNumber":414,"sourceCode":"\n                if key_kid:\n                    self._jwks_cache[key_kid] = public_key\n                else:\n                    # Key without kid - use a default identifier\n                    self._jwks_cache[\"_default\"] = public_key\n\n            self._jwks_cache_time = current_time\n\n            # Select the appropriate key\n            if kid:\n                if kid not in self._jwks_cache:\n                    if kid in skipped_kids:\n                        self.logger.debug(\n                            \"JWKS key lookup failed: key ID '%s' is present \"\n                            \"but its key type is unsupported\",\n                            kid,\n                        )\n                        raise ValueError(\n                            f\"Key ID '{kid}' found in JWKS but its key type \"\n                            \"is unsupported\"\n                        )\n                    self.logger.debug(\n                        \"JWKS key lookup failed: key ID '%s' not found\", kid\n                    )\n                    raise ValueError(f\"Key ID '{kid}' not found in JWKS\")\n                return self._jwks_cache[kid]\n            else:\n                # No kid in token - only allow if there's exactly one key\n                if len(self._jwks_cache) == 1:\n                    return next(iter(self._jwks_cache.values()))\n                elif len(self._jwks_cache) > 1:\n                    raise ValueError(\n                        \"Multiple keys in JWKS but no key ID (kid) in token\"\n                    )\n                else:\n                    raise ValueError(\"No keys found in JWKS\")","sourceCodeStart":396,"sourceCodeEnd":432,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/auth/providers/jwt.py#L396-L432","documentation":"The token's kid was matched against the JWKS and the key exists, but the library only supports certain key types (kty values, e.g. RSA/EC). A key with an unsupported kty — such as OKP or an exotic type — was skipped during lookup, so no usable verification key was found. This indicates a mismatch between your identity provider's key configuration and the algorithms this verifier supports.","triggerScenarios":"Calling verify_token on a JWT whose kid matches a JWKS entry whose kty (or algorithm) is outside the supported set, causing _get_jwks_key to raise after skipping that kid.","commonSituations":"Identity provider rotates to a new key type (e.g. EdDSA/OKP keys) while the verifier only accepts RSA/EC; misconfigured IdP publishes a signing key of an unexpected type; upgrading the IdP defaults without checking the JWKS contents.","solutions":["Inspect your JWKS (curl the jwks_uri) and check the kty field of the key with the matching kid","Configure your identity provider to sign tokens with a supported key type/algorithm (e.g. RS256 with an RSA key)","If the IdP must use the unsupported key type, use a verifier/algorithm configuration that supports it or pre-convert the key","Pin the token algorithm explicitly in the verifier config so the intended supported key is selected"],"exampleFix":"// before (IdP signs with EdDSA/OKP, verifier expects RSA)\n// after: force IdP signing algorithm to RS256 with an RSA key, then\ntokens = idp.issue(signing_alg=\"RS256\", signing_key=rsa_key)\n","handlingStrategy":"validation","validationCode":"import httpx, jwt\njwks = httpx.get(jwks_uri).json()\nheader = jwt.get_unverified_header(token)\nentry = next((k for k in jwks[\"keys\"] if k.get(\"kid\") == header.get(\"kid\")), None)\nif entry and entry.get(\"kty\") not in (\"RSA\", \"EC\"):\n    raise RuntimeError(f\"JWKS key {entry['kid']} has unsupported kty={entry['kty']}\")","typeGuard":"def is_supported_key(entry: dict) -> bool:\n    return entry.get(\"kty\") in (\"RSA\", \"EC\")","tryCatchPattern":"try:\n    claims = await verifier.verify_token(token)\nexcept ValueError as e:\n    if \"key type is unsupported\" in str(e):\n        # IdP key type not supported: reconfigure IdP or verifier algorithms\n        raise RuntimeError(\"IdP signing key type unsupported by verifier\") from e\n    raise","preventionTips":["Periodically fetch the JWKS and alert on keys with unsupported kty","Pin the IdP signing algorithm (e.g. RS256) in the provider settings","Review verifier-supported algorithms when upgrading the IdP or enabling new signing keys"],"tags":["auth","jwt","jwks","key-type"],"backgroundTag":"unsupported-jwks-key-type","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}