{"record":{"id":"b633a88aac98ced3","repo":"siyuan-note/siyuan","slug":"oauth-revocation-endpoint-returned-s","errorCode":null,"errorMessage":"OAuth revocation endpoint returned %s","messagePattern":"OAuth revocation endpoint returned (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/client/oauth.go","lineNumber":768,"sourceCode":"\t\t}\n\t\tvalues := url.Values{\"token\": {token.value}, \"token_type_hint\": {token.hint}}\n\t\tapplyOAuthClientAuthentication(values, nil, credential)\n\t\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, credential.RevocationEndpoint, strings.NewReader(values.Encode()))\n\t\tif err != nil {\n\t\t\tresult = errors.Join(result, err)\n\t\t\tcontinue\n\t\t}\n\t\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\t\tapplyOAuthClientAuthentication(nil, req, credential)\n\t\tresp, err := client.Do(req)\n\t\tif err != nil {\n\t\t\tresult = errors.Join(result, err)\n\t\t\tcontinue\n\t\t}\n\t\tio.Copy(io.Discard, io.LimitReader(resp.Body, 1<<20))\n\t\tresp.Body.Close()\n\t\tif resp.StatusCode < 200 || resp.StatusCode >= 300 {\n\t\t\tresult = errors.Join(result, fmt.Errorf(\"OAuth revocation endpoint returned %s\", resp.Status))\n\t\t}\n\t}\n\tif result != nil {\n\t\tlogging.LogWarnf(\"mcp oauth: revoke credentials failed: %s\", result)\n\t}\n\treturn result\n}\n\nfunc isSecureOAuthEndpoint(endpoint string) bool {\n\tparsed, err := url.Parse(endpoint)\n\tif err != nil {\n\t\treturn false\n\t}\n\tif parsed.Scheme == \"https\" {\n\t\treturn true\n\t}\n\tif parsed.Scheme != \"http\" {\n\t\treturn false","sourceCodeStart":750,"sourceCodeEnd":786,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/mcp/client/oauth.go#L750-L786","documentation":"The OAuth revocation endpoint replied with a non-2xx status while revoking the refresh or access token. The HTTP status text is wrapped in the returned error and joined across both token revocation attempts; revocation failure is also logged as a warning but still returned to the caller.","triggerScenarios":"POST to the revocation endpoint returns 400/401/404/5xx — e.g. the token was already revoked, the client credentials are wrong for RFC 7009 revocation, or the endpoint path in server metadata is stale.","commonSituations":"Revoking an already-expired/revoked token (some IdPs return 400), IdP rotated its revocation path, clock/auth issues causing 401, or the IdP not implementing RFC 7009 at the advertised endpoint.","solutions":["Read resp.Status in the error and check the IdP logs for the actual rejection reason","If the token was already revoked, treat the outcome as idempotent success on your side and ignore the joined error","Re-fetch OAuth discovery metadata so RevocationEndpoint matches the current server","Confirm client_id/client_secret sent with the revocation request are accepted by the IdP"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"resp, err := client.Post(revocationEndpoint, \"application/x-www-form-urlencoded\", strings.NewReader(body))\nif err == nil && resp.StatusCode >= 200 && resp.StatusCode < 300 {\n    // safe to proceed\n}","typeGuard":null,"tryCatchPattern":"err := revokeOAuthCredential(ctx, client, cred)\nif err != nil {\n    var statusErr interface{ Error() string }\n    if strings.Contains(err.Error(), \"OAuth revocation endpoint returned\") {\n        // token may already be revoked; log and treat as best-effort\n        logging.LogWarnf(\"revocation non-2xx, continuing: %s\", err)\n    }\n}","preventionTips":["Treat revocation as idempotent — an already-revoked token often yields 400","Re-run OAuth discovery when the IdP changes endpoints","Confirm RFC 7009 support on the authorization server before relying on revocation"],"tags":["oauth","http","revocation"],"backgroundTag":"http-error-response","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}