Authentication and access
This page explains how sessions work, how roles combine, and which headers the API client attaches. The real system stitches Next.js middleware, a Zustand auth store, an axios interceptor, and NestJS guards.
Sign-in and sign-up
| Flow | FE route | Summary |
|---|---|---|
| Email/password | /login | Returns accessToken, user, org list on success |
| Register | /register | Name, email, password; optional organizationId in some setups |
| Forgot password | /forgot-password | Email reset per backend policy |
| Google OAuth | Button on login | Requires NEXT_PUBLIC_GOOGLE_CLIENT_ID and @react-oauth/google |
Auth routes skip the main shell via ConditionalLayout (no sidebar).
Two role types — do not mix them
1) Account role (User.role)
From JWT / user record:
| Value | Meaning |
|---|---|
USER | Standard user |
SUPERADMIN | Platform ops; messaging environment instances menu |
2) Organization membership role
A user can belong to multiple orgs with different roles:
| Value | Meaning |
|---|---|
ORG_ADMIN | Invites, org settings, most admin CRUD |
MEMBER | Create/read per policy; project creation often restricted |
API RoleGuard / @Roles generally checks membership role. Example: POST /projects typically needs ORG_ADMIN plus subscription projetcs.
Super admin + projects
If the super admin account sees empty projects or 403, the backend may require an org context for project routes. Do day-to-day project work as an org member. See Concepts and architecture.
Multi-organization
- Login or
/users/me-style endpoints returnorganizations[]. - The organization switcher shows plain text when only one org; dropdown when multiple.
- On change,
OrganizationService.switchOrganizationruns; on success it updatesactiveOrganizationId, alignsuser.organizationId, and invalidates React Query caches.
Tokens and storage
token-storage:
- Writes access tokens to localStorage and cookie (
access_token, SameSite=Lax, ~7 days); user JSON is duplicated (userkey). - Reads cookie first, then localStorage for cross-subdomain SSO (
NEXT_PUBLIC_COOKIE_DOMAIN, e.g..cereinsight.com).
Middleware only sees the cookie, not localStorage on the first navigation.
Axios client (apiClient)
Per-request headers:
Authorization: Bearer <token>X-Organization-Id: <uuid>fromorganizationStorage.getActiveOrganizationId()
401 interceptor:
- If URL is not
/auth/login|register|forgot-password|reset-password:tokenStorage.clear()(token, user, active org id),- redirect to
/login.
Invalid password attempts therefore do not wipe a session; an expired JWT browsing the app does.
Protected routes (Next.js middleware)
src/middleware.ts rules (summary):
- Cookie present + auth path → redirect
/. - Cookie missing + non-public path → redirect
/login. /_next,/api, static extensions pass through.
Local dev
With empty cookie domain, cross-port localhost can desync cookies vs localStorage — middleware may send you to /login even if axios still has a token. Prefer same-origin dev proxy or verify the cookie is written.
Profile and language
User.language may exist. UI strings come from useTranslation() / locale files in your product codebase policy.
Security practices
- Redact JWTs in screenshots.
- Sign out on shared machines;
tokenStorage.clear()removes cookie + storage. - Keep API secrets server-side only.