{"record":{"id":"692acc61a3a81169","repo":"PrefectHQ/fastmcp","slug":"invalid-request","errorCode":"invalid_request","errorMessage":"invalid_request: Invalid redirect_uri.","messagePattern":"invalid_request: Invalid redirect_uri\\.","errorType":"error_code","errorClass":"AuthorizeError","httpStatus":400,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/auth/providers/in_memory.py","lineNumber":121,"sourceCode":"        \"\"\"\n        if client.client_id not in self.clients:\n            raise AuthorizeError(\n                error=\"unauthorized_client\",\n                error_description=f\"Client '{client.client_id}' not registered.\",\n            )\n\n        # Validate redirect_uri (already validated by AuthorizationHandler, but good practice)\n        try:\n            # OAuthClientInformationFull should have a method like validate_redirect_uri\n            # For this test provider, we assume it's valid if it matches one in client_info\n            # The AuthorizationHandler already does robust validation using client.validate_redirect_uri\n            if client.redirect_uris and params.redirect_uri not in client.redirect_uris:\n                # This check might be too simplistic if redirect_uris can be patterns\n                # or if params.redirect_uri is None and client has a default.\n                # However, the AuthorizationHandler handles the primary validation.\n                pass  # Let's assume AuthorizationHandler did its job.\n        except Exception as e:  # Replace with specific validation error if client.validate_redirect_uri existed\n            raise AuthorizeError(\n                error=\"invalid_request\", error_description=\"Invalid redirect_uri.\"\n            ) from e\n\n        auth_code_value = f\"test_auth_code_{secrets.token_hex(16)}\"\n        expires_at = time.time() + DEFAULT_AUTH_CODE_EXPIRY_SECONDS\n\n        # Ensure scopes are a list\n        scopes_list = params.scopes if params.scopes is not None else []\n        if client.scope:  # Filter params.scopes against client's registered scopes\n            client_allowed_scopes = set(client.scope.split())\n            scopes_list = [s for s in scopes_list if s in client_allowed_scopes]\n\n        if client.client_id is None:\n            raise AuthorizeError(\n                error=\"invalid_client\", error_description=\"Client ID is required\"\n            )\n        auth_code = AuthorizationCode(\n            code=auth_code_value,","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/auth/providers/in_memory.py#L103-L139","documentation":"Inside authorize, redirect_uri validation is wrapped in a try/except; if any exception occurs while validating that the requested redirect_uri is acceptable for the client, the provider raises AuthorizeError('invalid_request', 'Invalid redirect_uri.'). In the current implementation the check body largely passes validation through to the AuthorizationHandler, so this fires when validation raises unexpectedly.","triggerScenarios":"authorize() is called and the redirect_uri validation block raises — e.g. params.redirect_uri is malformed/None in a way that breaks validation, or client.redirect_uris contains values that make the comparison throw.","commonSituations":"Client sends a redirect_uri not pre-registered and an upstream/strict validation layer rejects it; tests feed params with a missing redirect_uri while client metadata requires one; encoding/whitespace differences between registered and requested URIs.","solutions":["Ensure params.redirect_uri exactly matches one of the URIs in the client's registered redirect_uris (scheme, host, port, path)","Check the exception chained via `from e` in logs to see the underlying validation failure","Register the desired redirect URI via register_client before authorizing"],"exampleFix":"// before\nparams = AuthorizationParams(redirect_uri=None, ...)  # client requires exact URIs\nprovider.authorize(client, params)\n// after\nparams = AuthorizationParams(redirect_uri=\"http://localhost:8080/callback\", ...)\nprovider.authorize(client, params)","handlingStrategy":"validation","validationCode":"redirect_uri = \"http://localhost:8080/callback\"\nassert redirect_uri in (client.redirect_uris or []), f\"redirect_uri {redirect_uri} not registered\"\nparams = AuthorizationParams(redirect_uri=redirect_uri, ...)","typeGuard":"def redirect_allowed(client, redirect_uri: str | None) -> bool:\n    return redirect_uri is not None and redirect_uri in (client.redirect_uris or [])","tryCatchPattern":"try:\n    redirect = provider.authorize(client, params)\nexcept AuthorizeError as e:\n    if e.error == \"invalid_request\":\n        logger.error(\"redirect_uri %r rejected: %s\", params.redirect_uri, e.error_description)","preventionTips":["Register every redirect URI (including ports and trailing slashes) up front","Compare exact strings — no wildcard hosts or path suffixes","Inspect the chained exception (`__cause__`) when validation fails unexpectedly"],"tags":["oauth","redirect-uri","authorization"],"backgroundTag":"invalid-redirect-uri","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}