PrefectHQ/fastmcp · error · RuntimeError

Unexpected authorization response: {response.status_code}

Error message

Unexpected authorization response: {response.status_code}

What it means

After the pre-flight GET of the authorization URL, FastMCP only accepts 200 (HTML login page) or redirect statuses (302/303/307/308). Any other status — 401, 403, 500, 502, etc. — means the authorization endpoint answered in a way the OAuth flow cannot proceed with, so redirect_handler raises RuntimeError before opening the browser.

Source

Thrown at fastmcp_slim/fastmcp/client/auth/oauth.py:395

                "OAuth dynamic registration returned an expired client secret"
            )
        return await super()._perform_authorization()

    async def redirect_handler(self, authorization_url: str) -> None:
        """Open browser for authorization, with pre-flight check for invalid client."""
        # Pre-flight check to detect invalid client_id before opening browser
        async with self.httpx_client_factory() as client:
            response = await client.get(authorization_url, follow_redirects=False)

            # Check for client not found error (400 typically means bad client_id)
            if response.status_code == 400:
                raise ClientNotFoundError(
                    "OAuth client not found - cached credentials may be stale"
                )

            # OAuth typically returns redirects, but some providers return 200 with HTML login pages
            if response.status_code not in (200, 302, 303, 307, 308):
                raise RuntimeError(
                    f"Unexpected authorization response: {response.status_code}"
                )

        logger.info(f"OAuth authorization URL: {authorization_url}")
        webbrowser.open(authorization_url)

    async def callback_handler(self) -> AuthorizationCodeResult:
        """Handle OAuth callback and return the authorization code result."""
        # Create result container and event to capture the OAuth response
        result = OAuthCallbackResult()
        result_ready = anyio.Event()

        # Create server with result tracking
        server: Server = create_oauth_callback_server(
            port=self.redirect_port,
            host=self._callback_host,
            server_url=self.mcp_url,
            result_container=result,

View on GitHub (pinned to 1f02114297)

Solutions

  1. Check the logged authorization URL and hit it in a browser to see the actual response/error page.
  2. Verify the server's authorization server metadata (issuer URL) resolves to the correct authorize endpoint.
  3. Check for proxies/WAFs intercepting the request and allowlist the endpoint.
  4. Retry later if the provider is returning 5xx (outage).

Example fix

// before: issuer typo yields 404 from authorize endpoint
OAuth(mcp_url='https://mcp.example.com/mcp', api_base_url='https://auth.example.com')
// after: correct issuer so discovery returns a valid authorize endpoint
OAuth(mcp_url='https://mcp.example.com/mcp', api_base_url='https://auth.correct-tenant.example.com')
Defensive patterns

Strategy: fallback

Validate before calling

import httpx
resp = httpx.get(authorization_url, follow_redirects=False)
if resp.status_code not in (200, 302, 303, 307, 308):
    print(resp.status_code, resp.headers.get('location'), resp.text[:200])

Try / catch

try:
    async with client:
        await client.list_tools()
except RuntimeError as e:
    if 'Unexpected authorization response' in str(e):
        log_authorization_url_and_retry_later()  # provider outage / wrong endpoint
    raise

Prevention

When it happens

Trigger: redirect_handler receives a status code outside (200, 302, 303, 307, 308): e.g. the authorization server returns 401/403 (auth required on the authorize endpoint itself), 404 (wrong issuer/authorize path in discovery metadata), or 5xx (provider outage or proxy error).

Common situations: Misconfigured OIDC discovery metadata pointing at the wrong authorization endpoint; corporate proxy or WAF returning 403/502; identity provider down or returning 500; server behind auth gateway that rejects the pre-flight GET.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/21343fd4a31b0c9d. Report an issue: GitHub.