{"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":"exception","errorClass":null,"httpStatus":null,"severity":"error","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/9f775e8a12daef8255556097396f9b2739078892/kernel/mcp/client/oauth.go#L365-L401","documentation":"Authorize waits on a channel for the browser OAuth callback, with a fixed timeout (oauthAuthorizationTimeout). If neither the callback arrives nor the context is cancelled before the timer fires, the flow is abandoned and this error is returned. The pending flow is removed via the deferred removeOAuthFlow.","triggerScenarios":"Authorize() registered an oauthFlow and printed an authorization URL; the user never completed (or never opened) the consent page in the browser within oauthAuthorizationTimeout, so the timer.C branch fires.","commonSituations":"User missed or ignored the browser popup; machine suspended during the flow; slow IdP consent page; headless/remote server where the callback URL (127.0.0.1:<port>) is unreachable from the user's browser.","solutions":["Retry authorization and complete the consent flow promptly in the browser","Ensure the callback URL http://127.0.0.1:<kernel-port>/... is reachable from the browser used for login (local vs remote/SSH setups)","Check that the kernel's callback endpoint /api/ai/mcp/oauth/callback/<flowID> is not blocked by a proxy or firewall","If the IdP is very slow, increase oauthAuthorizationTimeout upstream"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Check reachability of the local callback endpoint before starting\nresp, err := http.Get(fmt.Sprintf(\"http://127.0.0.1:%s/api/ai/mcp/oauth/ping\", util.ServerPort))\nif err != nil { /* callback unreachable: fix port/proxy first */ }","typeGuard":null,"tryCatchPattern":"if err := h.Authorize(ctx, true); err != nil {\n    if strings.Contains(err.Error(), \"timed out\") {\n        // retry the flow; ensure the user completes the browser step promptly\n    }\n}","preventionTips":["Open the authorization URL immediately and complete consent in one sitting","Use a browser that can reach 127.0.0.1:<kernel-port> (local browser, not one on another machine)","Avoid suspending the machine mid-flow; disable aggressive popup blockers","On remote/headless setups, tunnel the localhost callback port"],"tags":["oauth","mcp","timeout","browser-callback"],"backgroundTag":"request-timeout","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}