Bier.Auth (bier v0.1.0)

Copy Markdown View Source

Per-request authentication context: JWT verification, role resolution, and the PostgREST request GUCs.

PostgREST runs every request inside a transaction that first establishes the authenticated role and a set of request.* settings, then runs the main query. Concretely, before the query it applies (transaction-local, all via set_config(name, value, true) — upstream never issues SET ROLE):

  • role — the JWT role claim, else db-anon-role;
  • request.jwt.claims — the claims JSON;
  • request.method / request.path;
  • request.headers — JSON of lowercased headers;
  • request.cookies — JSON of cookie pairs;
  • search_path<request schema> : <db-extra-search-path>, upstream's searchPathSql (Query/PreQuery.hs), the request's own schema first;
  • one app.settings.<name> per configured app_settings entry;

and then runs the db-pre-request proc (if configured), which may itself SET ROLE or RAISE to abort the request.

All the set_config calls are batched into ONE SELECT statement — a single network round trip — mirroring upstream, which pipelines its whole preamble. SQL functions then read the settings via current_setting('request.…').

Bier applies this context whenever auth is configured for the instance (jwt_secret or db_anon_role), for every exposed schema — matching PostgREST. When neither is set, requests run as the connecting role with no role switch or GUCs. applicable?/1 encodes that gate.

Summary

Functions

True when the per-request auth context (role switch + request GUCs + pre-request hook) should be applied — i.e. when auth is configured (jwt_secret or db_anon_role). Mirrors PostgREST, where the authenticator connects and every request assumes a role whenever auth is set up.

Extract the bearer token (scheme-insensitive) from Authorization, or nil.

Map a Postgrex.Error raised under the auth context to the error shape the fallback controller expects. A 42501 (insufficient privilege) on an anonymous request becomes a 401 with WWW-Authenticate: Bearer; on an authenticated role it stays a 403 (no header). Other errors pass through.

Resolve the auth context for a request, verifying the JWT.

Run fun (a 1-arity function receiving the transaction connection) inside a transaction that first applies the auth context and the optional pre-request hook. Returns the function's result (passed through Postgrex.transaction/2 semantics) or an {:error, …} from the setup.

Types

t()

@type t() :: %{
  role: String.t() | nil,
  anonymous?: boolean(),
  claims_json: String.t(),
  method: String.t(),
  path: String.t(),
  headers_json: String.t(),
  cookies_json: String.t(),
  schema: String.t() | nil
}

Functions

applicable?(config)

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

True when the per-request auth context (role switch + request GUCs + pre-request hook) should be applied — i.e. when auth is configured (jwt_secret or db_anon_role). Mirrors PostgREST, where the authenticator connects and every request assumes a role whenever auth is set up.

bearer_token(conn)

Extract the bearer token (scheme-insensitive) from Authorization, or nil.

map_error(arg1, err)

@spec map_error(t() | nil, term()) :: term()

Map a Postgrex.Error raised under the auth context to the error shape the fallback controller expects. A 42501 (insufficient privilege) on an anonymous request becomes a 401 with WWW-Authenticate: Bearer; on an authenticated role it stays a 403 (no header). Other errors pass through.

resolve(conn, config)

@spec resolve(Plug.Conn.t(), Bier.Config.t()) :: {:ok, t()} | {:error, term()}

Resolve the auth context for a request, verifying the JWT.

Returns {:ok, context} or {:error, reason} where reason is a JWT failure surfaced by Bier.Plugs.FallbackController.

with_context(tx, context, config, fun)

@spec with_context(term(), t(), Bier.Config.t(), (term() -> any())) ::
  {:ok, any()} | {:error, term()}

Run fun (a 1-arity function receiving the transaction connection) inside a transaction that first applies the auth context and the optional pre-request hook. Returns the function's result (passed through Postgrex.transaction/2 semantics) or an {:error, …} from the setup.

The caller is responsible for ending the transaction (commit/rollback) inside fun, matching the existing read/mutation/rpc execution code.