{"record":{"id":"21343fd4a31b0c9d","repo":"PrefectHQ/fastmcp","slug":"unexpected-authorization-response-response-statu","errorCode":null,"errorMessage":"Unexpected authorization response: {response.status_code}","messagePattern":"Unexpected authorization response: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/client/auth/oauth.py","lineNumber":395,"sourceCode":"                \"OAuth dynamic registration returned an expired client secret\"\n            )\n        return await super()._perform_authorization()\n\n    async def redirect_handler(self, authorization_url: str) -> None:\n        \"\"\"Open browser for authorization, with pre-flight check for invalid client.\"\"\"\n        # Pre-flight check to detect invalid client_id before opening browser\n        async with self.httpx_client_factory() as client:\n            response = await client.get(authorization_url, follow_redirects=False)\n\n            # Check for client not found error (400 typically means bad client_id)\n            if response.status_code == 400:\n                raise ClientNotFoundError(\n                    \"OAuth client not found - cached credentials may be stale\"\n                )\n\n            # OAuth typically returns redirects, but some providers return 200 with HTML login pages\n            if response.status_code not in (200, 302, 303, 307, 308):\n                raise RuntimeError(\n                    f\"Unexpected authorization response: {response.status_code}\"\n                )\n\n        logger.info(f\"OAuth authorization URL: {authorization_url}\")\n        webbrowser.open(authorization_url)\n\n    async def callback_handler(self) -> AuthorizationCodeResult:\n        \"\"\"Handle OAuth callback and return the authorization code result.\"\"\"\n        # Create result container and event to capture the OAuth response\n        result = OAuthCallbackResult()\n        result_ready = anyio.Event()\n\n        # Create server with result tracking\n        server: Server = create_oauth_callback_server(\n            port=self.redirect_port,\n            host=self._callback_host,\n            server_url=self.mcp_url,\n            result_container=result,","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/client/auth/oauth.py#L377-L413","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Check the logged authorization URL and hit it in a browser to see the actual response/error page.","Verify the server's authorization server metadata (issuer URL) resolves to the correct authorize endpoint.","Check for proxies/WAFs intercepting the request and allowlist the endpoint.","Retry later if the provider is returning 5xx (outage)."],"exampleFix":"// before: issuer typo yields 404 from authorize endpoint\nOAuth(mcp_url='https://mcp.example.com/mcp', api_base_url='https://auth.example.com')\n// after: correct issuer so discovery returns a valid authorize endpoint\nOAuth(mcp_url='https://mcp.example.com/mcp', api_base_url='https://auth.correct-tenant.example.com')","handlingStrategy":"fallback","validationCode":"import httpx\nresp = httpx.get(authorization_url, follow_redirects=False)\nif resp.status_code not in (200, 302, 303, 307, 308):\n    print(resp.status_code, resp.headers.get('location'), resp.text[:200])","typeGuard":null,"tryCatchPattern":"try:\n    async with client:\n        await client.list_tools()\nexcept RuntimeError as e:\n    if 'Unexpected authorization response' in str(e):\n        log_authorization_url_and_retry_later()  # provider outage / wrong endpoint\n    raise","preventionTips":["Verify the issuer/discovery metadata URL is correct before wiring up OAuth.","Manually open the authorization URL in a browser once to confirm the endpoint responds.","Check proxy/WAF rules for the authorize endpoint in corporate networks.","Monitor the identity provider's status for 5xx outages."],"tags":["oauth","http","authorization-server","network"],"backgroundTag":"unexpected-http-response","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}