siyuan-note/siyuan · warning
mcp oauth authorization required
Error message
mcp oauth authorization required
What it means
Sentinel error errOAuthAuthorizationRequired returned by mcpOAuthHandler.Authorize when the server returned a Bearer challenge, no usable stored credential exists (or refresh failed permanently and was cleared), and the current flow is non-interactive (e.g. background reconnect). It signals that a human-driven browser authorization is required and cannot be completed now.
Source
Thrown at kernel/mcp/client/oauth.go:47
"net/url"
"slices"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/modelcontextprotocol/go-sdk/auth"
"github.com/modelcontextprotocol/go-sdk/oauthex"
"github.com/siyuan-note/httpclient"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/conf"
"github.com/siyuan-note/siyuan/kernel/util"
"golang.org/x/oauth2"
)
const oauthAuthorizationTimeout = 5 * time.Minute
var errOAuthAuthorizationRequired = errors.New("mcp oauth authorization required")
type oauthCallbackResult struct {
Code string
State string
Error string
}
type oauthFlow struct {
State string
Issuer string
Result chan oauthCallbackResult
Expires time.Time
}
var oauthFlows = struct {
sync.Mutex
items map[string]*oauthFlow
}{items: map[string]*oauthFlow{}}View on GitHub (pinned to 251596fc0d)
Solutions
- Trigger an interactive connect from the UI so the OAuth handler can open the browser flow and capture the callback; the connect timeout automatically extends by oauthAuthorizationTimeout when interactive.
- Complete the browser authorization once; the resulting credential is stored and subsequent non-interactive reconnects will use refresh.
- If authorization keeps being required, check that the stored credential's Issuer matches the auth server's Issuer (mismatched issuers prevent refresh).
- Confirm the auth server supports PKCE S256 and the authorization_code grant, otherwise the interactive flow will also fail later in Authorize.
Defensive patterns
Strategy: validation
Validate before calling
// Determine whether OAuth will be required before non-interactive connect.
func needsOAuth(server conf.MCPServer) bool {
return server.Type == "http" && !hasAuthorizationHeader(server.Headers)
} Try / catch
// Compare with errors.Is against the sentinel.
if errors.Is(err, client.ErrOAuthAuthorizationRequired) { // (if exported)
// trigger interactive connect from UI
} Prevention
- Run the first connect interactively so the OAuth flow can complete and cache a token.
- For background reconnects, expect this sentinel and surface a 're-authorize' prompt to the user.
When it happens
Trigger: connectHTTP runs non-interactively (interactive == false), the MCP server responds 401 with an OAuth Bearer challenge, and either there is no stored credential, the stored credential's refresh failed permanently (credential was cleared), or the credential was rejected. Authorize sets runtime state 'authorization_required' and returns this sentinel.
Common situations: First time adding an OAuth-protected MCP server (no cached token) while the kernel reconnects in the background; refresh token expired/revoked and the user has not re-authorized; the credential was marked Rejected by the auth server.
Related errors
- parse OAuth challenge: %w
- server returned %s without an OAuth Bearer challenge
- OAuth authorization timed out
- OAuth flow is missing or expired
- server returned %s
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/9aad2bc8a65be829.
Report an issue: GitHub.