PostgreSQL implementation of Attesto.RefreshStore.
Rotation is one family-serialized transaction. The transaction locks the family with a transaction-scoped advisory lock, locks the parent row, marks the parent consumed with its authenticated retry state, and inserts the successor before it commits. A blocked caller therefore sees either the complete committed winner or a complete reuse record; it can never observe a consumed parent before its successor exists.
Positive retry state is authenticated-encrypted before the transaction. The
encryption key must be stable across every node that can serve the family.
Strict rotation stores only %{retry_until: now, recoverable: false} and
needs no encryption secret. Expired retry state is redacted by the sweeper,
while a consumed parent is retained until that deadline or its own expiry,
whichever comes first. Family revocation
is also recorded in the separate RefreshFamilyRevocation table, whose
tombstones are never swept.
Summary
Functions
Administratively binds existing families to an operator-asserted single issuer.
Strong primary read of a refresh record.
Persists a new unconsumed refresh token.
Serializes family revocation with inserts and rotations, durably records the tombstone, and removes every row in the family.
Atomically rotates parent_hash into child.
Types
Functions
Administratively binds existing families to an operator-asserted single issuer.
Requires assert_single_issuer: true. The default dry_run: true audits
without changing rows; dry_run: false applies the binding. Each family is
serialized with rotation and updated atomically, including authenticated
retry bundles. Existing different bindings fail closed and are never replaced.
Expiry, generation, revocation, and client-instance bindings are unchanged.
Reads family identifiers in bounded batches (batch_size: 100, maximum 1,000).
A failed family leaves that family untouched; previously committed families
remain safely bound, so the operation can be repeated after resolving errors.
The configured repo and schema prefix identify the complete trusted store whose provenance the operator asserts. This API does not establish historical client-instance keys for pre-upgrade attested families.
@spec get(Attesto.RefreshStore.token_hash()) :: {:ok, Attesto.RefreshStore.entry()} | :error
Strong primary read of a refresh record.
Revoked families are intentionally hidden from the protocol layer. The query is always executed through the configured primary repo and carries the configured Ecto prefix explicitly.
@spec insert(Attesto.RefreshStore.entry()) :: :ok | {:error, :family_revoked | :conflict}
Persists a new unconsumed refresh token.
Family revocation and (family_id, generation)/token uniqueness are checked
while holding the same family lock used by rotation and revocation.
@spec revoke_family(Attesto.RefreshStore.family_id()) :: :ok
Serializes family revocation with inserts and rotations, durably records the tombstone, and removes every row in the family.
@spec rotate( Attesto.RefreshStore.token_hash(), Attesto.RefreshStore.entry(), map(), keyword() ) :: {:ok, Attesto.RefreshStore.entry(), Attesto.RefreshStore.entry()} | {:reuse, Attesto.RefreshStore.entry()} | {:error, rotation_error()} | :error
Atomically rotates parent_hash into child.
The successor is protected before any database work. A positive successor
requires the stable refresh-successor secret; failure to protect it returns
:retry_state_unavailable without touching the database. Strict mode uses
an exact non-secret tombstone and remains usable without that secret.