PrefectHQ/fastmcp · error · AuthorizeError
invalid_request
invalid_request
Error message
invalid_request: Invalid redirect_uri.
What it means
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.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/providers/in_memory.py:121
"""
if client.client_id not in self.clients:
raise AuthorizeError(
error="unauthorized_client",
error_description=f"Client '{client.client_id}' not registered.",
)
# Validate redirect_uri (already validated by AuthorizationHandler, but good practice)
try:
# OAuthClientInformationFull should have a method like validate_redirect_uri
# For this test provider, we assume it's valid if it matches one in client_info
# The AuthorizationHandler already does robust validation using client.validate_redirect_uri
if client.redirect_uris and params.redirect_uri not in client.redirect_uris:
# This check might be too simplistic if redirect_uris can be patterns
# or if params.redirect_uri is None and client has a default.
# However, the AuthorizationHandler handles the primary validation.
pass # Let's assume AuthorizationHandler did its job.
except Exception as e: # Replace with specific validation error if client.validate_redirect_uri existed
raise AuthorizeError(
error="invalid_request", error_description="Invalid redirect_uri."
) from e
auth_code_value = f"test_auth_code_{secrets.token_hex(16)}"
expires_at = time.time() + DEFAULT_AUTH_CODE_EXPIRY_SECONDS
# Ensure scopes are a list
scopes_list = params.scopes if params.scopes is not None else []
if client.scope: # Filter params.scopes against client's registered scopes
client_allowed_scopes = set(client.scope.split())
scopes_list = [s for s in scopes_list if s in client_allowed_scopes]
if client.client_id is None:
raise AuthorizeError(
error="invalid_client", error_description="Client ID is required"
)
auth_code = AuthorizationCode(
code=auth_code_value,View on GitHub (pinned to 1f02114297)
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
Example fix
// before params = AuthorizationParams(redirect_uri=None, ...) # client requires exact URIs provider.authorize(client, params) // after params = AuthorizationParams(redirect_uri="http://localhost:8080/callback", ...) provider.authorize(client, params)
Defensive patterns
Strategy: validation
Validate before calling
redirect_uri = "http://localhost:8080/callback"
assert redirect_uri in (client.redirect_uris or []), f"redirect_uri {redirect_uri} not registered"
params = AuthorizationParams(redirect_uri=redirect_uri, ...) Type guard
def redirect_allowed(client, redirect_uri: str | None) -> bool:
return redirect_uri is not None and redirect_uri in (client.redirect_uris or []) Try / catch
try:
redirect = provider.authorize(client, params)
except AuthorizeError as e:
if e.error == "invalid_request":
logger.error("redirect_uri %r rejected: %s", params.redirect_uri, e.error_description) Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- CIMD redirect_uri must have a host: {uri!r}
- invalid_redirect_uri
- unauthorized_client
- invalid_client
- OAuth authorization failed: {error} - {error_desc}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/692acc61a3a81169.
Report an issue: GitHub.