# `Attesto.Revocation`
[🔗](https://github.com/XukuLLC/attesto/blob/v2.6.1/lib/attesto/revocation.ex#L1)

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`, only a matching `:client_id` may
revoke its family. A mismatch is the same no-op `:ok` response as an
unknown token, so the revocation endpoint does not reveal another client's
token state. A caller that cannot authenticate the client passes
`allow_missing_client_id?: true`. A token issued without a client binding
skips the check.

## Issuer binding

Passing `:issuer` confines revocation to a refresh family issued by that
exact authorization-server issuer. A mismatch, including a legacy token
with no issuer marker, is the same no-op `:ok` as an unknown token and never
mutates the family. Omitting `:issuer` preserves legacy core behavior.

## 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.

# `revoke`

```elixir
@spec revoke(module(), String.t(), keyword()) :: :ok
```

Revoke the refresh token `token` (and its whole family) via `store`.

Returns `:ok` whether or not the token existed (no-existence oracle).
When the token carries a `client_id`, a mismatch or an absent client without
`allow_missing_client_id?: true` is an indistinguishable no-op `:ok` and
never revokes the family.

Options: `:client_id` (the authenticated revoking client),
`:allow_missing_client_id?`, and `:issuer` (the expected authorization
server issuer).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
