{"record":{"id":"f3e8f300cdf416b7","repo":"PrefectHQ/fastmcp","slug":"missing-required-oidc-endpoints","errorCode":null,"errorMessage":"Missing required OIDC endpoints","messagePattern":"Missing required OIDC endpoints","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/auth/oidc_proxy.py","lineNumber":389,"sourceCode":"                )\n            if required_scopes is not None:\n                raise ValueError(\n                    \"Cannot specify 'required_scopes' when providing a custom token_verifier. \"\n                    \"Configure required scopes on your token verifier instead.\"\n                )\n\n        if isinstance(config_url, str):\n            config_url = AnyHttpUrl(config_url)\n\n        self.oidc_config = self.get_oidc_configuration(\n            config_url, strict, timeout_seconds\n        )\n        if (\n            not self.oidc_config.authorization_endpoint\n            or not self.oidc_config.token_endpoint\n        ):\n            logger.debug(f\"Invalid OIDC Configuration: {self.oidc_config}\")\n            raise ValueError(\"Missing required OIDC endpoints\")\n\n        revocation_endpoint = (\n            str(self.oidc_config.revocation_endpoint)\n            if self.oidc_config.revocation_endpoint\n            else None\n        )\n\n        # Use custom verifier if provided, otherwise create default JWTVerifier\n        if token_verifier is None:\n            # When verifying id_tokens:\n            # - aud is always the OAuth client_id (per OIDC Core §2), not\n            #   the API audience, so use client_id for audience validation.\n            # - id_tokens don't carry scope/scp claims, so don't pass\n            #   required_scopes to the verifier (scope enforcement happens\n            #   at the FastMCP token level instead).\n            verifier_audience = client_id if verify_id_token else audience\n            verifier_scopes = None if verify_id_token else required_scopes\n            token_verifier = self.get_token_verifier(","sourceCodeStart":371,"sourceCodeEnd":407,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/auth/oidc_proxy.py#L371-L407","documentation":"OIDCProxy fetches the provider's OpenID Connect discovery document from config_url and needs at minimum the authorization_endpoint and token_endpoint to run the OAuth flow. If the fetched discovery document lacks either, the configuration is unusable and the proxy raises ValueError during __init__.","triggerScenarios":"OIDCProxy(config_url=...) where the served .well-known/openid-configuration (or the manually built OIDCConfiguration) omits authorization_endpoint or token_endpoint.","commonSituations":"Pointing config_url at a non-OIDC URL (plain HTML page, wrong path); a partial/broken identity provider that only issues discovery for some endpoints; mocking config in tests with an incomplete payload; network middleware returning an error body that fails parsing into empty fields.","solutions":["Verify config_url returns a valid OIDC discovery document containing authorization_endpoint and token_endpoint (open config_url in a browser/curl).","Correct the URL — typically it should be the issuer root, e.g. https://provider.com/.well-known/openid-configuration or the base issuer URL depending on the provider.","If the provider truly lacks discovery, construct OIDCConfiguration manually with explicit endpoint URLs and pass that instead of config_url."],"exampleFix":"// before\nproxy = OIDCProxy(config_url=\"https://idp.example.com\")  # serves no discovery doc\n// after\nproxy = OIDCProxy(config_url=\"https://idp.example.com/.well-known/openid-configuration\")","handlingStrategy":"validation","validationCode":"import httpx\ncfg = httpx.get(config_url, timeout=5).json()\nmissing = [k for k in (\"authorization_endpoint\", \"token_endpoint\") if not cfg.get(k)]\nif missing:\n    raise ValueError(f\"Discovery doc missing: {missing}\")","typeGuard":"def is_valid_discovery(cfg: dict | None) -> bool:\n    return bool(cfg and cfg.get(\"authorization_endpoint\") and cfg.get(\"token_endpoint\"))","tryCatchPattern":"try:\n    proxy = OIDCProxy(config_url=url, client_id=cid)\nexcept ValueError as e:\n    if \"Missing required OIDC endpoints\" in str(e):\n        logger.error(f\"Discovery at {url} lacks authorization/token endpoints\")\n    raise","preventionTips":["curl the .well-known/openid-configuration URL during deployment config checks","Validate identity provider URLs in CI before shipping","Prefer passing the issuer root the provider documents, not a guessed path"],"tags":["python","oauth","openid-connect","discovery","configuration"],"backgroundTag":"oidc-discovery-missing-endpoints","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}