Skip to content

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

FlowFE routeSummary
Email/password/loginReturns accessToken, user, org list on success
Register/registerName, email, password; optional organizationId in some setups
Forgot password/forgot-passwordEmail reset per backend policy
Google OAuthButton on loginRequires 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:

ValueMeaning
USERStandard user
SUPERADMINPlatform ops; messaging environment instances menu

2) Organization membership role

A user can belong to multiple orgs with different roles:

ValueMeaning
ORG_ADMINInvites, org settings, most admin CRUD
MEMBERCreate/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 return organizations[].
  • The organization switcher shows plain text when only one org; dropdown when multiple.
  • On change, OrganizationService.switchOrganization runs; on success it updates activeOrganizationId, aligns user.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 (user key).
  • 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> from organizationStorage.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.

API reference

Next steps

Cere Insight 2.0 documentation