# `Attesto.CodeStore.ETS`
[🔗](https://github.com/XukuLLC/attesto/blob/v2.6.1/lib/attesto/code_store/ets.ex#L1)

Single-node ETS implementation of `Attesto.CodeStore`.

Codes live in an ETS table owned by a `GenServer` that sweeps expired rows
on a fixed interval. `take/1` uses `:ets.take/2`, which
fetches and deletes a row in one atomic step, so the single-use
guarantee holds against concurrent redemptions on a node. This is a
per-node store: a multi-node deployment MUST back `Attesto.CodeStore`
with a shared store (e.g. Postgres `DELETE ... RETURNING`) so a code
issued on one node can be redeemed (once) on another.

Successful redemptions support the optional `mark_consumed/2` reuse
contract. Markers for bounded refresh families live through their family
deadline; unbounded refresh-family markers remain sticky for the store's
lifetime. A no-refresh marker is retained for 24 hours, bounding memory
while covering the normal access-token replay-response window.

The store also indexes the JTI of an access token minted from a redeemed
code. On a later code replay, callers can revoke that token by code hash or
by the finalized refresh-family ID and query the revocation by JTI. Both the
linkage and revocation marker expire with the access token.

## Start options

  * `:sweep_interval_ms` (default `30_000`) - how often expired rows are
    bulk-deleted. Correctness does not depend on sweeping (`take/1`
    returns the row and `Attesto.AuthorizationCode` re-checks expiry);
    the sweeper only bounds table size.

## Wiring

    children = [Attesto.CodeStore.ETS]

then pass the module as the store:

    Attesto.AuthorizationCode.issue(Attesto.CodeStore.ETS, attrs)

# `access_token_revoked?`

```elixir
@spec access_token_revoked?(String.t()) :: boolean()
```

Return whether a linked, unexpired access-token JTI has been revoked.

# `record_access_token_for_code`

```elixir
@spec record_access_token_for_code(String.t(), String.t(), integer()) :: :ok
```

Link a minted access-token JTI to its redeemed code until token expiry.

# `reset`

```elixir
@spec reset() :: :ok
```

Clear every entry. Test-facing.

# `revoke_access_token_for_code`

```elixir
@spec revoke_access_token_for_code(String.t()) :: :ok
```

Revoke the unexpired access token linked to a code hash.

# `revoke_family_access_tokens`

```elixir
@spec revoke_family_access_tokens(String.t()) :: :ok
```

Revoke unexpired access tokens linked to a finalized refresh family.

# `start_link`

```elixir
@spec start_link(keyword()) :: GenServer.on_start()
```

---

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