Per-instance JWT verification-result cache (PostgREST jwt-cache-max-entries).
Caches only the expensive half of verification — Bier.JWT.decode_and_verify/2
(signature check + claims decode) — keyed by the raw bearer token. Temporal
and audience validation run on every request after the lookup
(Bier.JWT.validate_claims/3 in Bier.Auth), so a cached token still
starts failing the moment its exp passes; the cache itself never
invalidates on time, mirroring PostgREST v14.12's Auth.JwtCache. Failed
verifications are never inserted.
Layout
The GenServer owns one public ETS set whose handle lives in
:persistent_term under {Bier, :jwt_cache, name}. Request processes read
and set the SIEVE visited bit directly (lock-free hits); inserts and
evictions are serialized through the owner. Rows are
{token, claims, claims_json, visited?}.
Eviction: SIEVE
Insertion order is kept in the owner's state as a doubly-linked map
(token => {newer, older} plus head/tail/hand pointers). At capacity
the hand walks from the oldest entry toward newer ones, clearing visited
bits on survivors; the first unvisited entry is evicted (emitting
[:bier, :jwt_cache, :eviction]) and the hand parks at the next newer
entry, wrapping to the tail when it walks past the head.
A cache fault never fails a request: a missing table (instance without a
cache, or the owner mid-restart) or an unreachable owner degrades fetch/3
to calling verify_fun directly.
Summary
Functions
Returns a specification to start this module under a supervisor.
True when this config runs the cache: a secret and a positive max.
Look token up in name's cache, calling verify_fun on a miss and
inserting its successful result. Emits [:bier, :jwt_cache, :lookup] per
consultation. Without a running cache, delegates straight to verify_fun
(no events — PostgREST records no observations in no-cache mode).
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec enabled?(Bier.Config.t()) :: boolean()
True when this config runs the cache: a secret and a positive max.
@spec fetch(atom(), String.t(), (-> {:ok, map(), String.t()} | {:error, term()})) :: {:ok, map(), String.t()} | {:error, term()}
Look token up in name's cache, calling verify_fun on a miss and
inserting its successful result. Emits [:bier, :jwt_cache, :lookup] per
consultation. Without a running cache, delegates straight to verify_fun
(no events — PostgREST records no observations in no-cache mode).