{"record":{"id":"96aa42925a4019f2","repo":"siyuan-note/siyuan","slug":"oauth-authorization-timed-out","errorCode":null,"errorMessage":"OAuth authorization timed out","messagePattern":"OAuth authorization timed out","errorType":"http","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/mcp/client/oauth.go","lineNumber":383,"sourceCode":"\t\tIssuer:  asm.Issuer,\n\t\tResult:  make(chan oauthCallbackResult, 1),\n\t\tExpires: time.Now().Add(oauthAuthorizationTimeout),\n\t}\n\toauthFlows.Lock()\n\toauthFlows.items[flowID] = flow\n\toauthFlows.Unlock()\n\tdefer removeOAuthFlow(flowID, flow)\n\tsetMCPRuntimeStateForContext(ctx, h.server.ID, \"authorizing\", 0, \"\", authorizationURL)\n\n\tvar callback oauthCallbackResult\n\ttimer := time.NewTimer(oauthAuthorizationTimeout)\n\tdefer timer.Stop()\n\tselect {\n\tcase callback = <-flow.Result:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase <-timer.C:\n\t\treturn fmt.Errorf(\"OAuth authorization timed out\")\n\t}\n\tif callback.Error != \"\" {\n\t\treturn fmt.Errorf(\"OAuth authorization failed: %s\", callback.Error)\n\t}\n\tif callback.State != state {\n\t\treturn fmt.Errorf(\"OAuth state mismatch\")\n\t}\n\tif callback.Code == \"\" {\n\t\treturn fmt.Errorf(\"OAuth callback did not include an authorization code\")\n\t}\n\n\texchangeCtx := context.WithValue(ctx, oauth2.HTTPClient, h.client)\n\ttoken, err := config.Exchange(exchangeCtx, callback.Code,\n\t\toauth2.VerifierOption(verifier),\n\t\toauth2.SetAuthURLParam(\"resource\", prm.Resource))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"exchange OAuth authorization code: %w\", err)\n\t}","sourceCodeStart":365,"sourceCodeEnd":401,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/mcp/client/oauth.go#L365-L401","documentation":"Returned at oauth.go:382-383 when the 5-minute oauthAuthorizationTimeout timer fires before the OAuth callback channel receives a result. The flow waits on a select over flow.Result, ctx.Done(), and the timer; the user must complete browser consent and the callback must reach /api/ai/mcp/oauth/callback/<flowID> within the window.","triggerScenarios":"Interactive Authorize opened the authorization URL but CompleteMCPOAuth was never called (user did not finish consent), was called after the flow's Expires time, or the callback HTTP request never reached the kernel (firewall, wrong port, browser blocked the redirect to 127.0.0.1).","commonSituations":"User walked away from the browser; browser failed to open or open the wrong URL; the 127.0.0.1 callback port blocked by host firewall/AV; long AS login (MFA, SSO) exceeding 5 minutes; process restarted clearing the in-memory oauthFlows map before callback arrived.","solutions":["Re-initiate the authorization promptly and complete browser consent within the 5-minute window.","Confirm the kernel is reachable at http://127.0.0.1:<util.ServerPort> and that the AS redirects back to the exact callback URL shown in the authorization URL.","Disable host firewall/AV blocking of the loopback callback port.","If SSO/MFA routinely exceeds 5 minutes, request a longer oauthAuthorizationTimeout (source change) or pre-authenticate the AS session."],"exampleFix":"// before: user starts auth then leaves; flow times out\n// after: re-trigger Authorize and finish the browser consent immediately,\n// ensuring the redirect to http://127.0.0.1:<port>/api/ai/mcp/oauth/callback/<id> is allowed","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Interactive Authorize caller — treat timeout as retriable user action.\nerr := handler.Authorize(ctx, req, resp)\nif err != nil && strings.Contains(err.Error(), \"OAuth authorization timed out\") {\n    setMCPRuntimeStateForContext(ctx, serverID, \"authorization_required\", 0, \"authorization timed out; please retry\", \"\")\n    return // allow the user to re-trigger\n}","preventionTips":["Advise users to complete browser consent promptly after the authorization URL opens.","Ensure the loopback callback port is open so the redirect lands immediately.","Avoid starting an authorization flow you cannot promptly complete."],"tags":["oauth","mcp","timeout","interactive","callback","loopback"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}