PrefectHQ/fastmcp · error · RegistrationError
invalid_redirect_uri
invalid_redirect_uri
Error message
Redirect URI '{redirect_uri}' is not allowed. What it means
During dynamic client registration, every redirect URI the client declares is checked against the proxy's configured allowed patterns (_allowed_client_redirect_uris). Any URI failing pattern validation raises RegistrationError with code invalid_redirect_uri, so the registration is rejected before the client is stored.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/oauth_proxy/proxy.py:1014
# *client record*: `OAuthClientMetadata.application_type` defaults to
# "native", while `OAuthClientInformationFull.application_type` is
# `str | None` and defaults to None. Normalize the unset case back to
# "native" so a client that omits the field gets the RFC 7591 default
# recorded explicitly, on both the HTTP and direct-call paths.
pending_application_type = _pending_application_type.get()
if pending_application_type is not None:
client_info.application_type = pending_application_type
elif client_info.application_type is None:
client_info.application_type = "native"
application_type = client_info.application_type
if client_info.redirect_uris:
for redirect_uri in client_info.redirect_uris:
if not validate_redirect_uri(
redirect_uri=redirect_uri,
allowed_patterns=self._allowed_client_redirect_uris,
):
raise RegistrationError(
"invalid_redirect_uri",
f"Redirect URI '{redirect_uri}' is not allowed.",
)
# SEP-837: honor the client's declared application_type. "web"
# clients are restricted to non-loopback https redirect URIs.
if not is_redirect_uri_allowed_for_application_type(
redirect_uri,
application_type,
):
raise RegistrationError(
"invalid_redirect_uri",
f"Redirect URI '{redirect_uri}' is not allowed for "
f"application_type '{application_type}'.",
)
elif application_type == "web":
# Clients may omit redirect_uris and supply one at authorization,
# which falls back to the `http://localhost` placeholder below. A web
# client can never authorize against that placeholder (loopback httpView on GitHub (pinned to 1f02114297)
Solutions
- Register a redirect URI matching one of the configured allowed patterns
- Adjust OAuthProxy's allowed client redirect URI pattern configuration to include the needed scheme/host
- For local development, add a localhost loopback pattern explicitly
Example fix
// before
POST /register {"redirect_uris": ["http://localhost:6274/oauth/callback"]} // https-only proxy
// after
POST /register {"redirect_uris": ["https://app.example.com/oauth/callback"]} Defensive patterns
Strategy: validation
Validate before calling
import re
def uri_matches(uri: str, patterns: list[str]) -> bool:
return any(re.fullmatch(p.replace("*", ".*"), uri) for p in patterns)
payload = {"redirect_uris": ["https://app.example.com/cb"], ...}
assert all(uri_matches(u, ALLOWED_PATTERNS) for u in payload["redirect_uris"]), "URI not allowed" Type guard
def all_uris_allowed(uris: list[str] | None, patterns: list[str]) -> bool:
return bool(uris) and all(uri_matches(u, patterns) for u in uris) Try / catch
try:
proxy.register_client(client_info)
except RegistrationError as e:
if e.error == "invalid_redirect_uri":
return JSONResponse({"error": "invalid_redirect_uri", "error_description": str(e)}, status_code=400)
raise Prevention
- Verify each redirect URI against the proxy's allowed patterns before POSTing to /register
- Use the same scheme/host/path the production proxy is configured for
- For local dev, request a loopback pattern be added instead of guessing URIs
When it happens
Trigger: POSTing to the DCR /register endpoint (or calling register_client/_start_flow directly) with redirect_uris entries that match none of the allowed patterns — e.g. http loopback URIs when only https patterns are configured.
Common situations: CLI or local dev clients registering http://localhost:port/callback against a production proxy that only allows https; a typo in the redirect path; proxy configured with restrictive patterns after upgrade.
Related errors
- CIMD redirect_uri must have a host: {uri!r}
- client_id is required for client registration
- invalid_request
- The device authorization request expired
- The device authorization request was denied
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/3220052275b975d9.
Report an issue: GitHub.