Hmbown/CodeWhale · warning

has no remote revoke endpoint

Error message

{} has no remote revoke endpoint

What it means

Thrown by the remote revoke helper when `remote_revoke_url` returns None — the provider defines no revocation endpoint (RFC 7009), so the token cannot be revoked server-side. The caller should treat this as local-only removal.

Solutions

  1. Skip remote revocation and clear the locally stored token instead (treat as local logout)
  2. Check whether the provider exposes a vendor-specific revoke endpoint and configure it
  3. Enable the revocation endpoint on your identity provider if you control it

Example fix

// before
remote_revoke(provider, issuer, client_id, token)?; // bails without endpoint
// after
if let Err(e) = remote_revoke(provider, issuer, client_id, token) {
    if e.to_string().contains("no remote revoke endpoint") {
        clear_local_token(provider); // local logout only
    } else {
        return Err(e);
    }
}
Defensive patterns

Strategy: fallback

Validate before calling

// check capability before revoking remotely
const url = remoteRevokeUrl(params, issuer);
if (!url) {
  clearLocalToken(provider); // local logout only
  return;
}

Try / catch

try {
  await remoteRevoke(provider, issuer, clientId, token);
} catch (e) {
  if (String(e).includes('no remote revoke endpoint')) {
    clearLocalToken(provider); // treat as local logout
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling the revoke path for a provider whose `oauth_provider_params` has no revocation endpoint and whose discovery metadata lacks `revocation_endpoint`.

Common situations: Provider that does not implement RFC 7009 token revocation; self-hosted IdP with revocation disabled; issuer discovery document without a revocation endpoint.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/8d93a3dd73bbb862. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/oauth.rs:1041

            ("grant_type", "refresh_token"),
            ("client_id", client_id),
            ("refresh_token", refresh_token),
        ],
    )?;
    parse_oauth_form_response(status, &body, "refresh", params)
}

/// Best-effort remote revoke through the seam. Callers clear local
/// credentials regardless of this outcome.
pub(crate) fn revoke_remote_token_via(
    client: &dyn OAuthFormClient,
    params: &OAuthProviderParams,
    issuer: &str,
    client_id: &str,
    token: &str,
) -> Result<()> {
    let Some(revoke_url) = remote_revoke_url(params, issuer) else {
        bail!("{} has no remote revoke endpoint", params.display_name);
    };
    let (status, body) =
        client.post_form(&revoke_url, &[("token", token), ("client_id", client_id)])?;
    if !(200..300).contains(&status) {
        bail!(
            "{} OAuth revoke failed with HTTP {status}: {}",
            params.display_name,
            compact_form_error(&body)
        );
    }
    Ok(())
}

// ── PKCE browser login ────────────────────────────────────────────────

/// RFC 7636 S256 PKCE pair. Custom Debug: the verifier is exchanged for
/// bearer material and never prints.
#[derive(Clone)]

View on GitHub (pinned to 73e0f67d83)