Authentication
Better Auth, organizations, sessions, and the shared signing secret.
Authentication and organization membership are handled by
Better Auth, configured in packages/auth and
mounted by the server under /api/auth/*.
Organizations & dynamic access control
The organization plugin provides multi-tenancy — organizations, members,
invitations, and teams. On top of it, dynamic access control powers the RBAC
system: the statement, static roles, and runtime dynamic roles ("groups").
The RBAC source of truth (packages/auth/src/permissions.ts) is deliberately
server-free so it can be imported by both the server and the browser bundle —
never import the database or server code into it. See
Permissions.
Enterprise identity
Two further plugins cover enterprise sign-in, both configured per organization from the app rather than from the environment:
- SSO — OIDC (and, server-side, SAML) identity providers. Registration is restricted to organization owners/admins, and a provider stays inert until its e-mail domain is verified by DNS TXT record.
- SCIM — directory sync. Tokens are stored hashed, must belong to an
organization, and reach the server under
/api/auth/scim/v2/*— which is why the auth routes acceptPUT/PATCH/DELETEas well.
See Single Sign-On & SCIM for the setup flow.
Sessions & cookies
Sessions are cookie-based and signed with BETTER_AUTH_SECRET:
- Over HTTPS:
SameSite=None; Secure— supports web and API on different subdomains. - Over plain HTTP: falls back to
SameSite=Lax, so localhost and LAN pilots work without TLS.
One secret, several services
BETTER_AUTH_SECRET signs sessions and the page-scoped collab tokens. The collab service must
be given the same secret so it can verify those tokens. Keep it with your backups — a restore
can't validate existing sessions without it.
Rate limiting
The server applies per-IP rate limits, tuned separately for the API and the auth routes:
RATE_LIMIT_MAX— general API requests/minute.RATE_LIMIT_AUTH_MAX— auth routes/minute.RATE_LIMIT_SCIM_MAX— SCIM routes/minute. Deliberately much wider: a directory sync is one request per user from a single IP, which the auth ceiling would throttle within seconds.
White-labeling
APP_NAME sets the display name used in auth flows, so a deployment can present
its own product name.