siyuan-note/siyuan · error
server returned without an OAuth Bearer challenge
Error message
server returned %s without an OAuth Bearer challenge
What it means
After parsing the WWW-Authenticate challenges, Authorize requires at least one OAuth Bearer challenge to drive the authorization flow. If the response's challenges contain no Bearer scheme, it fails with 'server returned %s without an OAuth Bearer challenge', where %s is the HTTP status line. This guards against servers that return 401/403 without usable OAuth metadata.
Solutions
- Verify the endpoint actually speaks MCP with OAuth; if it uses API keys instead, configure the key in the server's Headers so the OAuth handler is skipped
- Check that a reverse proxy is not stripping WWW-Authenticate headers and fix its configuration
- Confirm the server URL points at the MCP endpoint, not a generic login page
- If you control the server, make it emit a Bearer WWW-Authenticate challenge on 401
Defensive patterns
Strategy: try-catch
Try / catch
err := handler.Authorize(ctx, req, resp)
if err != nil && strings.Contains(err.Error(), "without an OAuth Bearer challenge") {
// server does not offer OAuth; fall back to static header auth
configureStaticHeaders(server)
} Prevention
- Confirm the MCP server implements the OAuth authorization flow before relying on it
- Use static Authorization headers for servers that use API keys instead of OAuth
- Ensure reverse proxies do not strip WWW-Authenticate responses
- Point the server URL at the real MCP endpoint, not a gateway login page
When it happens
Trigger: An HTTP MCP server responds with 401/403 during Connect but its WWW-Authenticate headers lack a Bearer challenge (e.g. only Basic, or no challenge at all), so the OAuth handler cannot determine scope/authorization endpoints.
Common situations: Server uses non-OAuth auth (Basic auth, API key) while the client expected OAuth; misconfigured reverse proxy stripping the WWW-Authenticate header; server returning a plain 401 HTML error page from a gateway instead of the MCP OAuth flow.
Related errors
- mcp oauth authorization required
- parse OAuth challenge
- configuration is not initialized
- discover OAuth authorization server
- exchange OAuth authorization code
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/d0ff3ab146d8c5e2.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/client/oauth.go:192
func credentialToken(credential oauthCredential) *oauth2.Token {
return &oauth2.Token{
AccessToken: credential.AccessToken,
TokenType: credential.TokenType,
RefreshToken: credential.RefreshToken,
Expiry: credential.Expiry,
}
}
func (h *mcpOAuthHandler) Authorize(ctx context.Context, req *http.Request, resp *http.Response) (retErr error) {
defer resp.Body.Close()
defer io.Copy(io.Discard, io.LimitReader(resp.Body, 1<<20))
challenges, err := oauthex.ParseWWWAuthenticate(resp.Header.Values("WWW-Authenticate"))
if err != nil {
return fmt.Errorf("parse OAuth challenge: %w", err)
}
if !hasBearerChallenge(challenges) {
return fmt.Errorf("server returned %s without an OAuth Bearer challenge", resp.Status)
}
challengeError := bearerChallengeParam(challenges, "error")
if resp.StatusCode == http.StatusForbidden && challengeError != "insufficient_scope" {
return fmt.Errorf("server returned %s", resp.Status)
}
interactive := h.interactive.Load()
if interactive {
defer func() {
if retErr != nil && !errors.Is(retErr, context.Canceled) {
setMCPRuntimeStateForContext(ctx, h.server.ID, "authorization_required", 0, retErr.Error(), "")
}
}()
}
prm, err := discoverProtectedResource(ctx, challenges, req.URL.String(), h.client)
if err != nil {
return err
}View on GitHub (pinned to 9f775e8a12)