siyuan-note/siyuan · warning
OAuth authorization timed out
Error message
OAuth authorization timed out
What it means
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.
Source
Thrown at kernel/mcp/client/oauth.go:383
Issuer: asm.Issuer,
Result: make(chan oauthCallbackResult, 1),
Expires: time.Now().Add(oauthAuthorizationTimeout),
}
oauthFlows.Lock()
oauthFlows.items[flowID] = flow
oauthFlows.Unlock()
defer removeOAuthFlow(flowID, flow)
setMCPRuntimeStateForContext(ctx, h.server.ID, "authorizing", 0, "", authorizationURL)
var callback oauthCallbackResult
timer := time.NewTimer(oauthAuthorizationTimeout)
defer timer.Stop()
select {
case callback = <-flow.Result:
case <-ctx.Done():
return ctx.Err()
case <-timer.C:
return fmt.Errorf("OAuth authorization timed out")
}
if callback.Error != "" {
return fmt.Errorf("OAuth authorization failed: %s", callback.Error)
}
if callback.State != state {
return fmt.Errorf("OAuth state mismatch")
}
if callback.Code == "" {
return fmt.Errorf("OAuth callback did not include an authorization code")
}
exchangeCtx := context.WithValue(ctx, oauth2.HTTPClient, h.client)
token, err := config.Exchange(exchangeCtx, callback.Code,
oauth2.VerifierOption(verifier),
oauth2.SetAuthURLParam("resource", prm.Resource))
if err != nil {
return fmt.Errorf("exchange OAuth authorization code: %w", err)
}View on GitHub (pinned to 251596fc0d)
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.
Example fix
// before: user starts auth then leaves; flow times out // after: re-trigger Authorize and finish the browser consent immediately, // ensuring the redirect to http://127.0.0.1:<port>/api/ai/mcp/oauth/callback/<id> is allowed
Defensive patterns
Strategy: retry
Try / catch
// Interactive Authorize caller — treat timeout as retriable user action.
err := handler.Authorize(ctx, req, resp)
if err != nil && strings.Contains(err.Error(), "OAuth authorization timed out") {
setMCPRuntimeStateForContext(ctx, serverID, "authorization_required", 0, "authorization timed out; please retry", "")
return // allow the user to re-trigger
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- OAuth flow is missing or expired
- mcp oauth authorization required
- OAuth authorization failed: %s
- OAuth state mismatch
- OAuth callback did not include an authorization code
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/96aa42925a4019f2.
Report an issue: GitHub.