RFC 7009 - OAuth 2.0 Token Revocation, for refresh tokens.
Revoking a refresh token revokes its entire family (every token
descended from the same authorization), the same machinery refresh
rotation uses for reuse detection. This module is the deliberate
revocation entry point; it runs over an Attesto.RefreshStore.
No-existence oracle (RFC 7009 §2.2)
An invalid, expired, or unknown token does not produce an error:
revoke/3 returns :ok regardless of whether the token existed. A
revocation endpoint must not let a caller probe which tokens are live,
so revoking a token the store has never seen is indistinguishable from
revoking a real one.
Client binding (RFC 7009 §2.1)
When the token carries a client_id, revocation is fail-closed: the
caller MUST present a matching :client_id or the call returns
{:error, :unauthorized_client}, so one client cannot revoke another
client's tokens. A caller that cannot authenticate the client passes
allow_missing_client_id?: true. A token issued without a client
binding skips the check.
Access tokens
Attesto access tokens are stateless, short-lived JWTs, so there is no
per-token revocation list to consult; revoking them is a host concern
(rely on their short TTL, or maintain a jti denylist the resource
server checks). This module revokes the stateful, family-backed refresh
credential, which is what RFC 7009 revocation is primarily for.
Summary
Functions
Revoke the refresh token token (and its whole family) via store.
Types
Functions
@spec revoke(module(), String.t(), keyword()) :: :ok | {:error, revoke_error()}
Revoke the refresh token token (and its whole family) via store.
Returns :ok whether or not the token existed (no-existence oracle).
Returns {:error, :unauthorized_client} only when the token carries a
client_id and the presented :client_id does not match (or is absent
without allow_missing_client_id?: true).
Options: :client_id (the authenticated revoking client) and
:allow_missing_client_id?.