siyuan-note/siyuan · error
parse OAuth challenge
Error message
parse OAuth challenge: %w
What it means
In mcpOAuthHandler.Authorize, the WWW-Authenticate headers of the server's 401/403 response are parsed with oauthex.ParseWWWAuthenticate; if that parsing fails, the error is wrapped as 'parse OAuth challenge: %w'. It means the server sent a malformed RFC 6750/9449 challenge that the client cannot interpret, so the OAuth flow cannot proceed.
Solutions
- Inspect the server's WWW-Authenticate headers (curl -v) and fix the server's challenge formatting if you control it
- Check for a proxy/gateway rewriting the header and bypass or fix it
- Update the server to a version emitting RFC-compliant Bearer challenges
- Report the malformed challenge to the MCP server vendor if it is third-party
Defensive patterns
Strategy: try-catch
Try / catch
err := handler.Authorize(ctx, req, resp)
if err != nil && strings.HasPrefix(err.Error(), "parse OAuth challenge: ") {
// server sent a malformed WWW-Authenticate header
logging.LogWarnf("non-RFC OAuth challenge from %s: %s", server.URL, err)
// fail over: report to user / try alternative auth (e.g. static headers)
} Prevention
- Test the server's 401 response headers (curl -v) before integrating it
- Keep oauthex and the MCP client library updated for parser fixes
- Avoid proxies that rewrite or split WWW-Authenticate headers
- Prefer servers with standards-compliant OAuth metadata endpoints
When it happens
Trigger: An HTTP MCP server returns an auth-challenge response whose WWW-Authenticate header values cannot be parsed by oauthex (malformed parameters, invalid quoting, non-standard syntax).
Common situations: Non-conformant or beta MCP server implementations emitting broken WWW-Authenticate headers; a proxy/gateway mangling or duplicating the header; custom auth middleware producing non-RFC challenge syntax.
Related errors
- server returned without an OAuth Bearer challenge
- configuration is not initialized
- discover OAuth authorization server
- exchange OAuth authorization code
- mcp oauth authorization required
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/6229f52294ddbe33.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/client/oauth.go:189
return credentialToken(refreshed), nil
}
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)View on GitHub (pinned to 9f775e8a12)