{"record":{"id":"d0ff3ab146d8c5e2","repo":"siyuan-note/siyuan","slug":"server-returned-s-without-an-oauth-bearer-challen","errorCode":null,"errorMessage":"server returned %s without an OAuth Bearer challenge","messagePattern":"server returned (.+?) without an OAuth Bearer challenge","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/client/oauth.go","lineNumber":192,"sourceCode":"func credentialToken(credential oauthCredential) *oauth2.Token {\n\treturn &oauth2.Token{\n\t\tAccessToken:  credential.AccessToken,\n\t\tTokenType:    credential.TokenType,\n\t\tRefreshToken: credential.RefreshToken,\n\t\tExpiry:       credential.Expiry,\n\t}\n}\n\nfunc (h *mcpOAuthHandler) Authorize(ctx context.Context, req *http.Request, resp *http.Response) (retErr error) {\n\tdefer resp.Body.Close()\n\tdefer io.Copy(io.Discard, io.LimitReader(resp.Body, 1<<20))\n\n\tchallenges, err := oauthex.ParseWWWAuthenticate(resp.Header.Values(\"WWW-Authenticate\"))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse OAuth challenge: %w\", err)\n\t}\n\tif !hasBearerChallenge(challenges) {\n\t\treturn fmt.Errorf(\"server returned %s without an OAuth Bearer challenge\", resp.Status)\n\t}\n\tchallengeError := bearerChallengeParam(challenges, \"error\")\n\tif resp.StatusCode == http.StatusForbidden && challengeError != \"insufficient_scope\" {\n\t\treturn fmt.Errorf(\"server returned %s\", resp.Status)\n\t}\n\tinteractive := h.interactive.Load()\n\tif interactive {\n\t\tdefer func() {\n\t\t\tif retErr != nil && !errors.Is(retErr, context.Canceled) {\n\t\t\t\tsetMCPRuntimeStateForContext(ctx, h.server.ID, \"authorization_required\", 0, retErr.Error(), \"\")\n\t\t\t}\n\t\t}()\n\t}\n\n\tprm, err := discoverProtectedResource(ctx, challenges, req.URL.String(), h.client)\n\tif err != nil {\n\t\treturn err\n\t}","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/mcp/client/oauth.go#L174-L210","documentation":"Returned by mcpOAuthHandler.Authorize when the WWW-Authenticate header parsed successfully but contains no 'Bearer' scheme challenge. Without a Bearer challenge, SiYuan cannot start an OAuth flow, so it reports the HTTP status verbatim via %s.","triggerScenarios":"The 401 response carries a parseable challenge but only for a non-Bearer scheme (e.g. 'Basic', 'Digest'). hasBearerChallenge(challenges) returns false and Authorize returns this error including resp.Status.","commonSituations":"Endpoint protected by HTTP Basic auth instead of OAuth; reverse proxy in front of the MCP server enforcing Basic/Digest; server advertises a custom scheme; client expected OAuth but the deployment uses static credentials.","solutions":["If the endpoint uses Basic/static auth, supply it via server.Headers (e.g. {\"Authorization\":\"Basic <base64>\"}); hasAuthorizationHeader will then disable the OAuth path entirely.","If OAuth is expected, the MCP server must advertise a Bearer challenge — report the misconfiguration to the server operator.","Remove any proxy that is rewriting Bearer into Basic in front of the MCP server."],"exampleFix":"// before: endpoint uses Basic auth, OAuth path trips\n{\"type\":\"http\",\"url\":\"https://mcp.example.com\"}\n// after: supply static Authorization header, OAuth skipped\n{\"type\":\"http\",\"url\":\"https://mcp.example.com\",\"headers\":{\"Authorization\":\"Basic <base64-user-pass>\"}}","handlingStrategy":"validation","validationCode":"func hasBearerHeader(headers []string) bool {\n    for _, h := range headers {\n        if strings.HasPrefix(strings.ToLower(strings.TrimSpace(h)), \"bearer \") { return true }\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use static server.Headers for Basic/Digest auth instead of OAuth.","Confirm the MCP server actually advertises a Bearer challenge before expecting OAuth."],"tags":["mcp","oauth","http-headers","auth"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}