{"record":{"id":"347f0d1194fbe4d4","repo":"siyuan-note/siyuan","slug":"oauth-authorization-server-does-not-support-pkce-s","errorCode":null,"errorMessage":"OAuth authorization server does not support PKCE S256","messagePattern":"OAuth authorization server does not support PKCE S256","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/client/oauth.go","lineNumber":252,"sourceCode":"\t\t\tsetMCPRuntimeStateForContext(ctx, h.server.ID, \"oauth_retrying\", 0, \"\", \"\")\n\t\t\treturn nil\n\t\t}\n\t\tif !permanent {\n\t\t\treturn fmt.Errorf(\"refresh OAuth credentials: %w\", refreshErr)\n\t\t}\n\t\tcredential.AccessToken = \"\"\n\t\tcredential.RefreshToken = \"\"\n\t\tcredential.Expiry = time.Time{}\n\t\tif saveErr := putOAuthCredential(credential); saveErr != nil {\n\t\t\tlogging.LogWarnf(\"mcp oauth: clear invalid credentials failed: %s\", saveErr)\n\t\t}\n\t}\n\tif !interactive {\n\t\tsetMCPRuntimeStateForContext(ctx, h.server.ID, \"authorization_required\", 0, \"\", \"\")\n\t\treturn errOAuthAuthorizationRequired\n\t}\n\tif !slices.Contains(asm.CodeChallengeMethodsSupported, \"S256\") {\n\t\treturn fmt.Errorf(\"OAuth authorization server does not support PKCE S256\")\n\t}\n\tif len(asm.ResponseTypesSupported) > 0 && !slices.Contains(asm.ResponseTypesSupported, \"code\") {\n\t\treturn fmt.Errorf(\"OAuth authorization server does not support the authorization code response type\")\n\t}\n\tif len(asm.GrantTypesSupported) > 0 && !slices.Contains(asm.GrantTypesSupported, \"authorization_code\") {\n\t\treturn fmt.Errorf(\"OAuth authorization server does not support the authorization code grant\")\n\t}\n\n\tflowID := reusableOAuthFlowID(credential)\n\tif flowID == \"\" {\n\t\tflowID, err = secureRandomString(24)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tstate, err := secureRandomString(24)\n\tif err != nil {\n\t\treturn err","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/mcp/client/oauth.go#L234-L270","documentation":"Thrown during interactive OAuth authorization after the authorization server metadata (ASM) is fetched. The check at oauth.go:251 verifies that 'S256' is present in asm.CodeChallengeMethodsSupported. SiYuan's MCP OAuth client hard-requires PKCE with the S256 challenge method (it always calls oauth2.S256ChallengeOption), so an AS that omits or only offers 'plain' is rejected before any user-facing flow starts.","triggerScenarios":"Calling mcpOAuthHandler.Authorize in interactive mode against a server whose /.well-known/oauth-authorization-server advertises code_challenge_methods_supported without 'S256' (e.g. only ['plain'], or the field absent). Non-interactive mode returns earlier with errOAuthAuthorizationRequired and never reaches this check.","commonSituations":"Legacy OAuth2 servers that predate RFC 7636; servers that only allow 'plain' PKCE; a custom AS that forgot to list S256; AS metadata fetched from a stale/incorrect issuer URL that returns a different document.","solutions":["On the authorization server, enable and advertise S256 in code_challenge_methods_supported (e.g. Authelia, Keycloak, hydra all support it by default — verify the field is present in the metadata JSON).","Confirm the discovered issuer URL is the intended AS by checking the runtime-state / logs for which AuthorizationServers[0] was used; a wrong resource can pull the wrong AS metadata.","If the AS genuinely cannot support S256, switch to a different authorization server or have the operator upgrade it; SiYuan cannot fall back to 'plain' PKCE by design."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before launching interactive Authorize, fetch and inspect AS metadata once\n// to fail fast with an actionable message rather than mid-flow.\nasm, err := auth.GetAuthServerMetadata(ctx, issuerURL, http.DefaultClient)\nif err != nil { return err }\nif !slices.Contains(asm.CodeChallengeMethodsSupported, \"S256\") {\n    return fmt.Errorf(\"AS %s must enable PKCE S256 in code_challenge_methods_supported\", issuerURL)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pre-flight AS metadata before surfacing the authorization URL to the user so capability gaps are reported clearly.","Document that SiYuan requires S256 PKCE and authorization_code grant when onboarding a new MCP OAuth server.","Cache AS metadata briefly so repeated Authorize attempts don't re-fetch and re-fail on the same gap."],"tags":["oauth","mcp","pkce","s256","metadata","authorization-server"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}