siyuan-note/siyuan · error

OAuth authorization timed out

Error message

OAuth authorization timed out

What it means

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.

Solutions

  1. Retry authorization and complete the consent flow promptly in the browser
  2. Ensure the callback URL http://127.0.0.1:<kernel-port>/... is reachable from the browser used for login (local vs remote/SSH setups)
  3. Check that the kernel's callback endpoint /api/ai/mcp/oauth/callback/<flowID> is not blocked by a proxy or firewall
  4. If the IdP is very slow, increase oauthAuthorizationTimeout upstream
Defensive patterns

Strategy: retry

Validate before calling

// Check reachability of the local callback endpoint before starting
resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%s/api/ai/mcp/oauth/ping", util.ServerPort))
if err != nil { /* callback unreachable: fix port/proxy first */ }

Try / catch

if err := h.Authorize(ctx, true); err != nil {
    if strings.Contains(err.Error(), "timed out") {
        // retry the flow; ensure the user completes the browser step promptly
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/96aa42925a4019f2. Report an issue: GitHub.

Appendix: 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 9f775e8a12)