Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Auth Collections

Any collection can be an auth collection. Set auth = true for defaults, or provide a configuration table.

Simple Auth

crap.collections.define("users", {
    auth = true,
    -- ...
})

Auth Config Table

crap.collections.define("users", {
    auth = {
        token_expiry = 3600,       -- 1 hour (default: 7200 = 2 hours)
        disable_local = false,      -- set true to disable password login
        strategies = {
            {
                name = "api-key",
                authenticate = "hooks.auth.api_key_check",
            },
        },
    },
    -- ...
})

Config Properties

PropertyTypeDefaultDescription
token_expiryinteger7200JWT token lifetime in seconds. Overrides the global [auth] token_expiry.
disable_localbooleanfalseWhen true, the password login form is hidden. Only custom strategies can authenticate.
verify_emailbooleanfalseWhen true, new users must verify their email before logging in. Requires email configuration.
forgot_passwordbooleantrueWhen true, enables the “Forgot password?” flow. Requires email configuration.
strategiesAuthStrategy[]{}Custom auth strategies. See Custom Strategies.

Email Auto-Injection

When auth = true and no email field exists in the field definitions, one is automatically injected:

crap.fields.email({
    name = "email",
    required = true,
    unique = true,
    admin = { placeholder = "user@example.com" },
})

If you define your own email field, it’s used as-is.

Password Storage

Auth collections get a hidden _password_hash TEXT column during schema migration. This column:

  • Is not a regular field — it doesn’t appear in def.fields
  • Is never returned in API responses
  • Is never included in hook contexts
  • Is never shown in admin forms
  • Is only accessed by dedicated auth functions (update_password, get_password_hash)

Password Policy

All password-setting paths (create, update, reset, CLI) enforce the password policy configured in [auth.password_policy] in crap.toml. Defaults: min 8 Unicode characters, max 128 bytes. min_length counts Unicode codepoints (so multi-byte characters count as 1). max_length counts bytes (to bound Argon2 hashing cost). See crap.toml reference for all options.

Password in Create/Update

When creating or updating a user, the password field (if present in the data) is:

  1. Extracted from the data before hooks run
  2. Hashed with Argon2id after the document is written
  3. Stored in the _password_hash column

In the admin UI:

  • Create form — password is required
  • Edit form — password is optional (“leave blank to keep current”)

Account Locking

Auth collections support a _locked system field. When a user’s _locked field is set to a truthy value (e.g., 1), that user is immediately denied access:

  • JWT validation — every authenticated request checks _locked after resolving the user from the token. A locked user’s token is effectively revoked, even if it hasn’t expired.
  • Me RPC — returns an unauthenticated error for locked users.
  • Admin UI — the session is rejected and the user is redirected to the login page.

Locking takes effect immediately — no token refresh or logout is needed. Use the CLI to lock/unlock users:

crap-cms -C ./my-project user lock -e admin@example.com
crap-cms -C ./my-project user unlock -e admin@example.com

JWT Claims

Tokens contain:

ClaimDescription
subUser document ID
collectionAuth collection slug (e.g., “users”)
emailUser email
expExpiration timestamp (Unix)
iatIssued-at timestamp (Unix)