Bier.JwtCache (bier v0.1.0)

Copy Markdown View Source

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

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

enabled?(config)

@spec enabled?(Bier.Config.t()) :: boolean()

True when this config runs the cache: a secret and a positive max.

fetch(name, token, verify_fun)

@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).

start_link(conf)