Skip to content

feat(auth): PostgREST-faithful auth gate#70

Merged
milmazz merged 7 commits into
mainfrom
feat/postgrest-faithful-auth-gate
Jul 14, 2026
Merged

feat(auth): PostgREST-faithful auth gate#70
milmazz merged 7 commits into
mainfrom
feat/postgrest-faithful-auth-gate

Conversation

@milmazz

@milmazz milmazz commented Jul 14, 2026

Copy link
Copy Markdown
Owner

What & why

Bier's per-request auth context (role switch, request.* GUCs, db-pre-request) previously activated only for a schema literally named authBier.Auth.applicable?/1 hardcoded schema == "auth". That meant db_anon_role, jwt_secret, and db-pre-request were inert for any other schema, so a host app couldn't expose a naturally named api schema with role-based access the way PostgREST's tutorials do.

This makes the gate faithful to PostgREST: the auth context now applies to every exposed schema whenever auth is configured (jwt_secret or db_anon_role). When neither is set, requests run as the connecting role with no role switch — so unauthenticated deployments are unaffected.

Changes

  • lib/bier/auth.exapplicable?/1 now takes the config and returns config.jwt_secret != nil or config.db_anon_role != nil (was schema == "auth"). Moduledoc updated.
  • lib/bier/plugs/action_controller.exmaybe_auth/3 gates on the config. The root OpenAPI document (GET /) previously resolved auth unconditionally; it now serves the full document unfiltered when auth is not configured (filter_by_mode/5 treats a nil role as "no privilege filtering"). The nil-role branch is reachable only off the no-auth path — Bier.Auth.resolve never returns a nil role — so conformance output is unchanged.
  • test/support/conformance_server.ex — the shared conformance fixture DB connects as a superuser and grants the anon role almost nothing, so switching roles across the non-auth areas would 42501. That compromise moves into the harness: the single shared instance is split into a no-auth bulk instance (base_opts/0, byte-identical superuser behavior) and an auth-configured auth instance (auth_opts/0), with cases routed by schema in ["auth","openapi"] or path == "/". spec/** is untouched.
  • test/bier/auth_applicable_test.exs — new unit test for applicable?/1.

Verification

  • Full mix test: 822 passed, 5 excluded, 0 failures (entire conformance suite + test/bier/*, incl. unix_socket_test).
  • mix format --check-formatted, mix credo --strict, mix docs --warnings-as-errors — all clean.

Follow-up (out of scope)

Connecting as an authenticator login role with per-role GRANTs (instead of a superuser) remains future work. This PR unblocks the upcoming brewery tutorial/docs PR, which relies on a natural api schema getting role-switching.

Branch also carries the design spec and implementation plans under docs/superpowers/ (internal planning artifacts).

🤖 Generated with Claude Code

milmazz and others added 7 commits July 13, 2026 23:47
Design for the pre-release documentation pass: two tutorials (Getting
Started, Authentication) and three reference guides (API, Configuration,
Observability), driven by an original brewery-catalog example. Includes
the enabling lib change that generalizes the auth gate via a new
db_auth_schemas option so the auth tutorial can expose a natural 'api'
schema while keeping the conformance suite green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-faithful auth gate

PR 1 makes Bier.Auth.applicable? gate on whether auth is configured
(jwt_secret/db_anon_role) rather than a hardcoded schema name, matching
PostgREST, and moves the shared-fixture-DB compromise into the conformance
harness via a two-instance (bulk/auth) split + url_for routing predicate.
PR 2 (dependent) adds the brewery example DB and the five ex_doc pages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bier.Auth.applicable? now returns true whenever auth is configured
(jwt_secret or db_anon_role), so role switching, request GUCs, and the
db-pre-request hook apply to every exposed schema — matching PostgREST —
instead of only a schema literally named 'auth'.

The shared conformance fixture DB connects as a superuser and grants the
anon role almost nothing, so role-switching in the bulk areas would 42501.
That compromise moves into the harness: the shared instance splits into a
no-auth 'bulk' instance and an auth-configured 'auth' instance, with cases
routed by schema/path. spec/ is untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-up to fbaf8e0: the dispatch_root comment described only the
auth-configured path; note that with no auth configured the full OpenAPI
document is served unfiltered (role = nil).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
After gating maybe_auth on the config instead of the schema name, the
schema argument was dead (kept only to avoid caller churn). Remove it and
update both call sites (relation + RPC dispatch); refresh the stale comment
that still described the auth-schema-only behavior.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extract role resolution into root_doc_role/2 so the document is built and
served once, instead of duplicating the build+encode+send across both
branches of the auth-configured/no-auth conditional. No behavior change: an
auth failure still short-circuits via the with.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@milmazz
milmazz merged commit 768cb83 into main Jul 14, 2026
3 checks passed
@milmazz
milmazz deleted the feat/postgrest-faithful-auth-gate branch July 14, 2026 06:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant