Skip to Content
Apps & PortalsAuthSessions & Tokens

Sessions & Tokens

How Leadmetrics issues, validates, and refreshes authentication tokens across web portals and the mobile app.

Related: Auth Overview | API Auth Endpoints


Token Types

TokenLifetimeFormatStoragePurpose
Access token15 minutesSigned JWT (HS256)httpOnly cookie per portalAuthorize API requests
Refresh token7 daysOpaque (random string)httpOnly cookie per portalObtain a new access token

Access tokens are verified locally by each portal’s middleware (no database lookup). Refresh tokens are stored in the database and can be revoked.


JWT Payload

{ sub: string; // user ID (ULID) role: string; // 'admin' | 'member' | 'reviewer' | 'super_admin' appAccess: string[]; // apps the user is allowed to access tenantId?: string; // absent for super_admin name?: string; email?: string; iat: number; // issued at (Unix seconds) exp: number; // iat + 900 (15 min) }

Signing algorithm: HS256 (HMAC-SHA256) with JWT_SECRET. The same secret is used by the Fastify API (to sign) and all portal middleware (to verify).


Session Lifecycle

User logs in loginAction() → POST /auth/v1/login Access token (15 min) + Refresh token (7 days) set as httpOnly cookies ▼ (token expires) Next.js middleware intercepts 401 POST /auth/v1/refresh → new access token ├── Success → new cookie set, request continues └── Failure → redirect to /login

Silent Refresh

When a request arrives with an expired access token, the Next.js middleware (createJwtAuthMiddleware from @leadmetrics/middleware) transparently refreshes it:

  1. Reads the access token cookie — JWT verify fails (expired)
  2. Reads the refresh token cookie
  3. Calls POST /auth/v1/refresh with the refresh token
  4. On success: sets a new access token cookie, forwards the request
  5. On failure (refresh token missing, expired, or revoked): redirects to /login

The user never sees an error — the refresh is completely transparent.


Middleware Configuration per Portal

Each portal passes a defaultPath option to createJwtAuthMiddleware. This controls the callbackUrl used when an unauthenticated user visits / — after login they land on that path. Without it, the factory defaults to /dashboard, which only exists in the dashboard app.

PortaldefaultPath
dashboard (:3000)(omit — factory default /dashboard is correct)
manage (:3001)/dashboards/overview
DM (:3002)/overview

Each portal’s middleware.ts must keep its export const config as an inline literal — Next.js cannot statically analyse imported values for the matcher.


All auth cookies are set with:

HttpOnly — not accessible to JavaScript Secure — HTTPS only (production) SameSite — Lax (allows top-level navigation) Path — /

Logout

Calling logoutAction() (which calls POST /auth/v1/logout):

  1. API deletes the refresh token record from the database
  2. clearAuthCookies() deletes both the access and refresh token cookies from the browser
  3. User is redirected to /login

After logout, the access token cookie is gone. Even if a previously issued access token were somehow retained, it expires within 15 minutes and cannot be refreshed (the refresh token is revoked).


Password Reset

Password reset uses a one-time token delivered by email:

POST /auth/v1/forgot-password { email } → API sends reset email with token (1-hour expiry) → User clicks link → /reset-password?token=<token> POST /auth/v1/reset-password { token, newPassword } → API validates token, hashes new password, deletes token

Tokens are stored in the verification table. Duplicate requests for the same email are suppressed for 20 minutes. Rate limit: 5 requests per 15 minutes.


Mobile Sessions

Mobile uses the same HS256 JWT system. Access tokens are stored in secure device storage (not cookies). The mobile app calls POST /auth/v1/refresh directly when the access token expires.

See Mobile Patterns for the mobile-specific refresh implementation.


Features Planned but Not Yet Implemented

  • RS256 asymmetric signing with JWKS endpoint
  • Refresh token rotation (currently refresh tokens are not rotated on use)
  • Token revocation beyond logout
  • Biometric device tokens
  • Two-factor authentication
  • Session list / remote revoke endpoints
  • Email verification on registration
  • HIBP breach-check on password set

© 2026 Leadmetrics — Internal use only