Postgres-backed AttestoPhoenix.PARStore for clustered deployments
(RFC 9126).
A Pushed Authorization Request endpoint stores the validated authorization
request parameters behind a one-time request_uri reference and returns that
reference to the client; the client then presents only the request_uri at
/authorize. The default AttestoPhoenix.Store.PAR.ETS keeps that mapping in
per-node memory, so a request_uri pushed to one node is unknown to another -
fatal behind a load balancer, and FAPI 2.0 requires PAR. This store persists
each pushed request so any node resolves a request_uri issued by any other,
matching the Ecto-backed code/refresh/nonce/replay stores.
Behaviour callbacks
put/3inserts the reference, the stored params, and the derived expiry.fetch/1resolves a live (unexpired) reference WITHOUT consuming it - the authorization endpoint may re-enter with the samerequest_uriafter a login/consent detour (RFC 9126), so resolution must not spend it. Expiry is enforced on read, so an unswept expired reference is never honored.take/1resolves and atomically deletes a live reference in oneDELETE … RETURNINGstatement, for hosts that want single-use semantics. Exactly one of any number of racing callers gets the row.
The repository module is supplied by the host application (:repo under the
:attesto_phoenix app) and read at call time; a store with no backing
repository fails closed rather than silently no-opping.
Summary
Functions
Resolves a live request_uri without consuming it.
Persists a pushed authorization request under request_uri for
ttl_seconds.
Atomically resolves and deletes a live request_uri.
Functions
Resolves a live request_uri without consuming it.
Returns {:ok, params} when a row exists and has not expired, or :error
when it is absent or expired. Non-consuming by contract: the authorization
endpoint may resolve the same request_uri more than once across a
login/consent detour (RFC 9126); TTL, not resolution, ends its life.
@spec put(String.t(), map(), pos_integer()) :: :ok | {:error, term()}
Persists a pushed authorization request under request_uri for
ttl_seconds.
params is the stored, string-keyed parameter map; it is round-tripped
through jsonb, so the authorization endpoint reads back the same string-keyed
map it stored. A duplicate request_uri (an astronomically unlikely random
collision) surfaces as {:error, changeset} rather than overwriting an
existing reference.
Atomically resolves and deletes a live request_uri.
The resolve and the delete are one indivisible DELETE … WHERE … RETURNING
statement, so for hosts that opt into single-use PAR references exactly one of
any number of concurrent callers (on any node) gets {:ok, params}; the rest
get :error. An expired row is treated as absent.