siyuan-note/siyuan · error
parse OAuth challenge: %w
Error message
parse OAuth challenge: %w
What it means
Returned by mcpOAuthHandler.Authorize when oauthex.ParseWWWAuthenticate cannot parse the WWW-Authenticate header(s) on a 401 response. The wrapped parse error explains the syntactic problem. Without a parseable challenge list, the OAuth flow cannot discover the authorization server.
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 251596fc0d)
Solutions
- curl -i the endpoint and inspect the raw WWW-Authenticate header; confirm it is a syntactically valid Bearer challenge.
- If the server uses a non-Bearer scheme, OAuth cannot be used — set server.Headers with a static Authorization (or other) header instead, which disables the OAuth path via hasAuthorizationHeader.
- Report the malformed header to the MCP server operator if the server is supposed to be OAuth-compliant.
- If a proxy rewrites the header, bypass or reconfigure the proxy for this endpoint.
Example fix
# expected (well-formed) WWW-Authenticate: Bearer realm="api", error="invalid_token" # malformed example that triggers the error WWW-Authenticate: Please authenticate
Defensive patterns
Strategy: validation
Validate before calling
// Verify the WWW-Authenticate header shape before relying on OAuth.
import "github.com/modelcontextprotocol/go-sdk/oauthex"
func probeChallenge(url string) error {
// fetch the endpoint, get a 401, then:
// _, err := oauthex.ParseWWWAuthenticate(resp.Header.Values("WWW-Authenticate"))
return nil
} Prevention
- curl -i the endpoint to inspect WWW-Authenticate before configuring OAuth.
- If the header is non-standard, switch to static Authorization headers.
When it happens
Trigger: The MCP HTTP server returns 401 with one or more WWW-Authenticate header values that are not valid RFC 6750/7235 challenge strings (malformed auth-scheme, unquoted parameters, stray tokens). ParseWWWAuthenticate returns an error and Authorize wraps it.
Common situations: Server sends a custom auth scheme instead of Bearer; header is a free-form string like 'Please log in'; proxy injected a malformed challenge; server-side bug producing unquoted parameters; multiple WWW-Authenticate headers with conflicting schemes.
Related errors
- server returned %s without an OAuth Bearer challenge
- mcp oauth authorization required
- server returned %s
- discover OAuth authorization server: %w
- OAuth authorization server metadata not found
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/6229f52294ddbe33.
Report an issue: GitHub.