Sign-in and users

Users are a regular collection with auth built in. No separate auth service: accounts, sessions and permissions live in the same binary as the data they protect.

Signing in

app.ts
const users = sluurp.collection("users");
await users.authWithPassword(email, password);

sluurp.authStore.record;   // the signed-in user
sluurp.logout();

Sign-in returns a token valid for 14 days; authRefresh() exchanges it for a fresh one. Passwords need at least 8 characters and are stored as Argon2 hashes.

Magic linkrequestSigninLink(email): passwordless. Single-use, and expires
Password resetrequestPasswordReset(email) emails a link; confirmPasswordReset(token, password) sets the new password
OAuthGoogle, GitHub, Microsoft, GitLab, or any OpenID Connect provider, configured under Sign-in in the admin UI. Redirect with location.href = users.oauthUrl("google") and call captureOAuthToken(sluurp) on the return page
Two-factorA 6-digit TOTP code after the first factor. Five wrong attempts end the attempt

There are no recovery codes: a user who loses their phone asks an admin, who disables 2FA on their record and signs them out everywhere.

Who may join

An app-level setting, enforced by the server:

  • invite (default): invitation only.
  • open: anyone can sign up, subject to the collection’s create rule.
  • closed: no sign-ups, for accounts synced from a directory.

An invitation has two parts. The inviter sets fields like organisation and role, which the invitee can’t change. The invitee fills in the rest: name, password.

app.ts
await users.invite("parent@example.com", {
  fields: { org: school.id, roles: ["parent"] },
  collect: ["first_name", "last_name"],
});

Roles

A user’s roles is a list that rules can check: @request.auth.roles ~ "teacher". Only whole roles match, so “admin” never matches “superadmin”.

For administrators

  • Impersonate a user from their record in the admin UI to see the app as they do.
  • Sign out everywhere: revoking a user’s tokens ends all their sessions immediately.
  • Superusers are separate from app users: create one with sluurp superuser EMAIL PASSWORD.