feat(auth): PostgREST-faithful auth gate#70
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Bier's per-request auth context (role switch,
request.*GUCs,db-pre-request) previously activated only for a schema literally namedauth—Bier.Auth.applicable?/1hardcodedschema == "auth". That meantdb_anon_role,jwt_secret, anddb-pre-requestwere inert for any other schema, so a host app couldn't expose a naturally namedapischema 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_secretordb_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.ex—applicable?/1now takes the config and returnsconfig.jwt_secret != nil or config.db_anon_role != nil(wasschema == "auth"). Moduledoc updated.lib/bier/plugs/action_controller.ex—maybe_auth/3gates 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/5treats a nil role as "no privilege filtering"). The nil-role branch is reachable only off the no-auth path —Bier.Auth.resolvenever 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 would42501. That compromise moves into the harness: the single shared instance is split into a no-authbulkinstance (base_opts/0, byte-identical superuser behavior) and an auth-configuredauthinstance (auth_opts/0), with cases routed byschema in ["auth","openapi"] or path == "/".spec/**is untouched.test/bier/auth_applicable_test.exs— new unit test forapplicable?/1.Verification
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
authenticatorlogin 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 naturalapischema getting role-switching.Branch also carries the design spec and implementation plans under
docs/superpowers/(internal planning artifacts).🤖 Generated with Claude Code