siyuan-note/siyuan · error
OAuth revocation endpoint must use HTTPS or loopback HTTP
Error message
OAuth revocation endpoint must use HTTPS or loopback HTTP
What it means
The configured OAuth revocation endpoint URL is not HTTPS and is not a loopback HTTP address. `isSecureOAuthEndpoint` requires HTTPS for any non-loopback host so that refresh/access tokens sent during revocation are never transmitted in cleartext over a network.
Source
Thrown at kernel/mcp/client/oauth.go:741
for _, credential := range credentials {
if err := revokeOAuthCredential(ctx, client, credential); err != nil {
revokeErr = errors.Join(revokeErr, err)
}
}
if revokeErr != nil {
logging.LogWarnf("mcp oauth: revoke credentials for server [%s] failed: %s", serverID, revokeErr)
}
}()
}
return nil
}
func revokeOAuthCredential(ctx context.Context, client *http.Client, credential oauthCredential) error {
if credential.RevocationEndpoint == "" {
return nil
}
if !isSecureOAuthEndpoint(credential.RevocationEndpoint) {
return fmt.Errorf("OAuth revocation endpoint must use HTTPS or loopback HTTP")
}
var result error
for _, token := range []struct {
value string
hint string
}{{credential.RefreshToken, "refresh_token"}, {credential.AccessToken, "access_token"}} {
if token.value == "" {
continue
}
values := url.Values{"token": {token.value}, "token_type_hint": {token.hint}}
applyOAuthClientAuthentication(values, nil, credential)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, credential.RevocationEndpoint, strings.NewReader(values.Encode()))
if err != nil {
result = errors.Join(result, err)
continue
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
applyOAuthClientAuthentication(nil, req, credential)View on GitHub (pinned to 251596fc0d)
Solutions
- Correct the IdP's published revocation endpoint metadata to use `https://`.
- If testing locally, point the revocation endpoint at `http://localhost:...` or `http://127.0.0.1:...` (loopback is permitted).
- Ensure the reverse proxy advertises the public `https://` URL in metadata even when it forwards internally over HTTP.
Example fix
// before RevocationEndpoint: "http://idp.internal:8080/revoke" // after RevocationEndpoint: "https://idp.internal/revoke"
Defensive patterns
Strategy: validation
Validate before calling
// Enforce HTTPS (or loopback) before storing a revocation endpoint.
func assertSecureRevokeURL(endpoint string) error {
u, err := url.Parse(endpoint)
if err != nil {
return err
}
if u.Scheme == "https" {
return nil
}
if u.Scheme == "http" && (strings.EqualFold(u.Hostname(), "localhost") || net.ParseIP(u.Hostname()).IsLoopback()) {
return nil
}
return errors.New("revocation endpoint must use HTTPS or loopback HTTP")
} Prevention
- Always prefer https:// for revocation endpoints in published metadata.
- Use loopback http:// only for local development.
- Make reverse proxies advertise their public https:// URL.
When it happens
Trigger: `revokeOAuthCredential` is called (during `DisconnectMCPOAuth`) with a credential whose `RevocationEndpoint` scheme is `http://` pointing at a non-localhost host, or an unsupported scheme like `ftp`.
Common situations: On-premise/dev IdP advertising an `http://` revocation endpoint. A mis-pasted revocation URL missing the `s` in `https://`. A reverse proxy that terminates TLS but whose published metadata still lists the internal `http://` URL.
Related errors
- OAuth state mismatch
- OAuth issuer mismatch
- mcp oauth authorization required
- parse OAuth challenge: %w
- server returned %s without an OAuth Bearer challenge
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/c40f9a8090040649.
Report an issue: GitHub.