{"record":{"id":"e54ce92b16a07617","repo":"PrefectHQ/fastmcp","slug":"cannot-specify-required-scopes-when-providing-a","errorCode":null,"errorMessage":"Cannot specify 'required_scopes' when providing a custom token_verifier. Configure required scopes on your token verifier instead.","messagePattern":"Cannot specify 'required_scopes' when providing a custom token_verifier\\. Configure required scopes on your token verifier instead\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/auth/oidc_proxy.py","lineNumber":373,"sourceCode":"        if not client_secret and not jwt_signing_key:\n            raise ValueError(\n                \"Either client_secret or jwt_signing_key must be provided. \"\n                \"jwt_signing_key is required when client_secret is omitted \"\n                \"(e.g., for PKCE public clients).\"\n            )\n\n        if not base_url:\n            raise ValueError(\"Missing required base URL\")\n\n        # Validate that verifier-specific parameters are not used with custom verifier\n        if token_verifier is not None:\n            if algorithm is not None:\n                raise ValueError(\n                    \"Cannot specify 'algorithm' when providing a custom token_verifier. \"\n                    \"Configure the algorithm on your token verifier instead.\"\n                )\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 = (","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/auth/oidc_proxy.py#L355-L391","documentation":"OIDCProxy accepts a custom token_verifier to control token validation. When one is supplied, the proxy delegates all validation (including which algorithm to use and which scopes are required) to that verifier, so passing 'algorithm' or 'required_scopes' to the constructor would be contradictory/ignored. The library raises ValueError at construction time to force you to configure these on your verifier instead.","triggerScenarios":"Constructing OIDCProxy with both a token_verifier argument and either required_scopes='...' (or algorithm='...') — e.g. OIDCProxy(config_url=..., client_id=..., token_verifier=MyVerifier(), required_scopes=['read']).","commonSituations":"Migrating from JWTVerifier/proxy-managed verification to a custom verifier while keeping the old constructor kwargs; copy-pasting example code that sets required_scopes and then adding a custom verifier for signature checks.","solutions":["Remove the required_scopes (and algorithm) arguments from the OIDCProxy constructor.","Implement required-scope checking inside your custom token verifier (e.g. in verify_token, check token.scope/claims['scp'] and raise TokenVerifier error if scopes missing).","If you don't need custom verification, drop token_verifier and let the proxy use required_scopes directly."],"exampleFix":"// before\nproxy = OIDCProxy(config_url=url, client_id=cid, token_verifier=MyVerifier(), required_scopes=[\"read\"])\n// after\nclass MyVerifier(TokenVerifier):\n    required_scopes = {\"read\"}\n    def verify_token(self, token):\n        ...  # enforce scopes here\nproxy = OIDCProxy(config_url=url, client_id=cid, token_verifier=MyVerifier())","handlingStrategy":"validation","validationCode":"def check_oidc_proxy_kwargs(kwargs):\n    if kwargs.get(\"token_verifier\") is not None and (kwargs.get(\"required_scopes\") or kwargs.get(\"algorithm\")):\n        raise ValueError(\"required_scopes/algorithm must be configured on the custom token_verifier\")","typeGuard":"def has_custom_verifier(proxy_kwargs: dict) -> bool:\n    return proxy_kwargs.get(\"token_verifier\") is not None","tryCatchPattern":"try:\n    proxy = OIDCProxy(**kwargs)\nexcept ValueError as e:\n    if \"token_verifier\" in str(e):\n        kwargs = {k: v for k, v in kwargs.items() if k not in (\"required_scopes\", \"algorithm\")}\n        proxy = OIDCProxy(**kwargs)\n    else:\n        raise","preventionTips":["Centralize scope/algorithm policy inside your TokenVerifier subclass","Never mix token_verifier with proxy-level validation kwargs in factory functions"],"tags":["python","configuration","oauth","constructor-validation"],"backgroundTag":"conflicting-auth-config","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}