{"record":{"id":"51692ab7a5f428ad","repo":"PrefectHQ/fastmcp","slug":"oidc-discovery-document-for-issuer-issuer-r-has","errorCode":null,"errorMessage":"OIDC discovery document for issuer {issuer!r} has no jwks_uri","messagePattern":"OIDC discovery document for issuer (.+?) has no jwks_uri","errorType":"exception","errorClass":"IdentityAssertionError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/auth/identity_assertion.py","lineNumber":301,"sourceCode":"                response = await client.get(config_url, timeout=10.0)\n                response.raise_for_status()\n                body = response.json()\n        except (httpx2.HTTPError, ValueError) as e:\n            self._discovery_failures[issuer] = time.monotonic()\n            raise IdentityAssertionError(\n                f\"OIDC discovery for issuer {issuer!r} failed: {e}\"\n            ) from e\n        if not isinstance(body, dict):\n            # Valid JSON that isn't an object (e.g. `[]` or a bare string) —\n            # guard before .get() so a misbehaving discovery endpoint maps to\n            # invalid_grant, not a 500 on every subsequent exchange.\n            raise IdentityAssertionError(\n                f\"OIDC discovery document for issuer {issuer!r} is not a JSON object\"\n            )\n\n        jwks_uri = body.get(\"jwks_uri\")\n        if not jwks_uri or not isinstance(jwks_uri, str):\n            raise IdentityAssertionError(\n                f\"OIDC discovery document for issuer {issuer!r} has no jwks_uri\"\n            )\n        return jwks_uri\n\n    async def _get_verifier(self, issuer: str) -> JWTVerifier:\n        from fastmcp.server.auth.providers.jwt import JWTVerifier as _JWTVerifier\n\n        verifier = self._verifiers.get(issuer)\n        if verifier is not None:\n            return verifier\n\n        jwks_uri = (self.config.jwks_uris or {}).get(issuer)\n        if not jwks_uri:\n            jwks_uri = await self._discover_jwks_uri(issuer)\n\n        algorithm = (self.config.algorithms or {}).get(issuer, self.config.algorithm)\n        verifier = _JWTVerifier(\n            jwks_uri=jwks_uri,","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/auth/identity_assertion.py#L283-L319","documentation":"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.","triggerScenarios":"validate() on an assertion whose issuer's discovery document has jwks_uri missing, empty, null, or a non-string JSON type (number/list/object).","commonSituations":"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.","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."],"exampleFix":"// before\n{\"issuer\": \"https://idp.example.com\"}\n// after\n{\"issuer\": \"https://idp.example.com\", \"jwks_uri\": \"https://idp.example.com/.well-known/jwks.json\"}","handlingStrategy":"validation","validationCode":"doc = httpx.get(issuer + '/.well-known/openid-configuration').json()\njwks_uri = doc.get('jwks_uri')\nassert isinstance(jwks_uri, str) and jwks_uri.startswith('https://')","typeGuard":"def has_jwks_uri(doc: dict) -> bool:\n    u = doc.get('jwks_uri')\n    return isinstance(u, str) and bool(u)","tryCatchPattern":"try:\n    await provider.validate(assertion)\nexcept IdentityAssertionError as e:\n    if 'no jwks_uri' in str(e):\n        log.error('IdP metadata missing jwks_uri; configure explicit JWKS')\n    raise","preventionTips":["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"],"tags":["oidc","discovery","jwks","configuration"],"backgroundTag":"oidc-discovery-missing-jwks-uri","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}