Accounts and authentication for apps
What native email and password accounts provide, how sessions and ownership work, and when to build another sign-in method.
Step-by-step guidance.
Before you start
- A managed backend service with a database binding in development and production.
- Read Fact statuses to interpret the Provided and Buildable labels.
When accounts are already requested
Logged-in users, save to my account and owner-scoped libraries require real authentication. Use the native account module or preserve existing authentication. Do not ask whether accounts should be real or block on a preferred sign-in method when the user has not requested a custom one. Verify login and cross-account rejection before polishing the dashboard.
Decide whether the app needs accounts
Accounts are opt-in. Add them only when the product needs signed-in users, per-user data, or private files. An app without accounts can still be built: mark its public routes explicitly and keep Rumata access rules separate from application users.
- Reuse the authentication an app already has. Do not add a second login system next to it.
- For a new app with unspecified file or data privacy, ask one question first: should data be private to signed-in accounts, or shared publicly? Do not silently build an anonymous app when privacy is undecided.
- Rumata permissions decide who can call a service or workflow. Application accounts decide which end user owns which record. They are different layers; neither replaces the other.
What native accounts provide
The Node.js API starter includes an opt-in native account module. It stores accounts in the factory’s PostgreSQL database and issues sessions that the starter’s authentication guard verifies on every protected request.
| Route | Purpose |
|---|---|
| `POST /auth/register` | Create an account from an email and password and return a session. |
| `POST /auth/login` | Verify an email and password and return a session. |
| `GET /auth/me` | Return the signed-in account’s `id` and `email` from its session. |
Passwords are stored as salted hashes. Sessions are signed with the factory’s own secret and last one hour. Use these routes instead of building UserRegister or UserLogin workflows or rewriting authentication.
Sessions last one hour
A session is a signed token with a lifetime of 3,600 seconds. The response carries the token, the user, and `expiresIn`. The native module defines no refresh, logout, or password-reset route, so an expired session means the user signs in again.
Derive ownership from request.user.id
The starter guard verifies the session signature, expiry and identity before a protected handler runs, then exposes the verified user as `request.user`. Every read, update and delete of owned data must filter by `request.user.id`, and every insert must take its owner from it.
- Never trust a user ID, owner field or claim sent in a request body, query string, header, or decoded on the client.
- Keep the starter’s guard in place. Mark only login, registration and genuinely public routes as public.
- Test that user B cannot read, change or delete user A’s records, and that an anonymous call is rejected.
What the native module provides
Statuses are defined in Fact statuses. Other sign-in methods are Buildable: the app’s backend can implement any authentication scheme. See Platform capabilities.
| Capability | Status | Detail |
|---|---|---|
| Email and password registration and login | Provided | Native module routes `/auth/register` and `/auth/login`. |
| One-hour signed sessions | Provided | 3,600-second sessions; no refresh route. |
| Per-user data ownership | Provided | Enforced by your backend using `request.user.id`. |
| Passwordless, one-time-code, magic-link or phone login | Buildable | Custom backend code. See Passwordless login. |
| Social or single sign-on login for app users | Buildable | Custom backend code with the identity provider’s OAuth or OIDC endpoints. |
| Password reset, email verification, multi-factor authentication | Buildable | Custom backend code; the native module has no such routes. |
| Keeping an existing authentication system | Provided | Preserve it and use an equivalent server-enforced ownership scope. |
Use the native module for email and password sign-in. Build a custom method when the product needs one.