Authentication basics
Authenticate the caller before evaluating permissions. Keep identity verification separate from authorization, use narrowly scoped credentials, and fail closed when the principal or required scope is missing.
What a signed-in consumer may read
Section titled “What a signed-in consumer may read”Signing in establishes who the consumer is; it does not by itself open a private model. A model
whose anonymous_access.read is false grants a signed-in consumer of the same application only
what its settings.consumer_reads says:
any_authenticated: every eligible row, even whenconsumer_owner_queryis also set.owner: only the rows the model’sconsumer_owner_queryreturns for the consumer;ownerwithout that query is rejected at save time (consumer_reads_owner_requires_owner_query).- absent or
off: unchanged legacy behavior. A configuredconsumer_owner_querystill scopes the consumer to its rows; without one the consumer reads no private rows.
The same decision applies on reference validation, edit-form loading, model-qualified record get
and list, public action targets, page bindings, and record pickers. A consumer signed into a
different application is treated as anonymous, and anonymous callers follow only
anonymous_access.read, so any_authenticated never opens a model to signed-out visitors and
never restricts a model that is already publicly readable. Reading grants nothing else:
consumer_writes alone decides consumer create, update, and delete, and a public record action
still needs the model’s public_record_actions permission. Model settings use replacement
semantics, so send the complete merged settings object. See row-level-security, “Set the
consumer read policy”, for the owner-query contract.
Registration outcomes
Section titled “Registration outcomes”Self-registration proves email ownership by default (identity_settings.registration_email_verification
is required). Handle all three modes and the duplicate case in every registration form:
required: the registration POST answers202withregistered: trueandemailVerification: "pending"and no session. Show “check your email”; do not redirect to a signed-in page. The user follows the mailed link, lands onverification_redirect_path(default/) withemail_verification=verified, and then signs in.optional: the usual session response withemailVerification: "sent"; the user is signed in andactor.email_verifiedstays false until the link is followed.off: the usual session response; the identity starts verified.- An email that already has an account gets the
requiredanswer underrequiredandoptional, and a value-free409underoff.
Page-builder form blocks on the identity model already present these outcomes. Turning on
required or optional needs an outbound sender; without one the settings save is refused.
Secure the sign-in
Section titled “Secure the sign-in”Email normalisation and uniqueness, enumeration-safe answers, rate limits, the per-account login
backoff, refresh rotation and revocation on password change are automatic. Choose the
verification mode, password_min_length and registration Turnstile, and wire forgot-password,
reset-password, change-password and sign-out-everywhere as described in
Secure authentication for your app (secure-authentication).
Never build reset or verification tokens from rules and records, and never list a password
field in a public record action.
