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(default30_000) - how often expired rows are bulk-deleted. Correctness does not depend on sweeping (take/1returns the row andAttesto.AuthorizationCodere-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)
Summary
Functions
Return whether a linked, unexpired access-token JTI has been revoked.
Link a minted access-token JTI to its redeemed code until token expiry.
Clear every entry. Test-facing.
Revoke the unexpired access token linked to a code hash.
Revoke unexpired access tokens linked to a finalized refresh family.
Functions
Return whether a linked, unexpired access-token JTI has been revoked.
Link a minted access-token JTI to its redeemed code until token expiry.
@spec reset() :: :ok
Clear every entry. Test-facing.
@spec revoke_access_token_for_code(String.t()) :: :ok
Revoke the unexpired access token linked to a code hash.
@spec revoke_family_access_tokens(String.t()) :: :ok
Revoke unexpired access tokens linked to a finalized refresh family.
@spec start_link(keyword()) :: GenServer.on_start()