JWT and Session Authentication

JWT Bearer Tokens

Token Issuance

JWTs are issued upon successful authentication via the following endpoints:

Endpoint Trigger
POST /api/public/signin Email + password authentication
POST /api/public/mfa/verify MFA completion (TOTP code)
POST /api/public/oauth/google Google OAuth credential exchange

Token Structure

Algorithm: HS256 (HMAC-SHA256)

Claims:

{
  "sub": "<user-id>",
  "tenant_id": "<tenant-uuid>",
  "role": "admin | user | regulator",
  "email": "<user-email>",
  "iat": 1708300000,
  "exp": 1708303600
}

Lifetimes:

  • Access token: 1 hour
  • Refresh token: 7 days

Token Refresh

Clients exchange a valid refresh token for a new access token via POST /api/public/refresh. The endpoint issues both a new access token and a new refresh token.

Token Blacklisting

When a user's tokens are revoked (password change, admin action, or explicit logout), all tokens issued before the revocation timestamp are rejected. Blacklist checking occurs after signature verification.

POST /api/v1/admin/revoke-user-tokens
Body: { "userId": "<uuid>", "reason": "Password changed" }

The blacklist is stored in the token_blacklist table. Verification checks isTokenRevoked(userId, issuedAt) against the repository.

Key Rotation

The platform supports zero-downtime key rotation via two environment variables:

Variable Purpose
JWT_SECRET Current signing and verification key (minimum 32 characters)
JWT_SECRET_PREV Previous key, accepted for verification only

During rotation, new tokens are signed with JWT_SECRET while tokens signed with the previous key remain valid until expiration.

Implemented in packages/auth/src/jwt.ts at commit 4b572c2.


Multi-Factor Authentication (MFA)

Setup Flow

  1. Client calls POST /api/public/mfa/setup (requires Bearer token)
  2. Server generates TOTP secret and returns { secret, otpauthUri }
  3. User scans QR code in authenticator app
  4. Client calls POST /api/public/mfa/verify-setup with TOTP code to confirm enrollment

Signin with MFA

  1. Client authenticates via POST /api/public/signin
  2. If MFA is enabled, server returns an intermediate MFA challenge (5-minute TTL)
  3. Client submits TOTP code to POST /api/public/mfa/verify
  4. On success, server issues full JWT + refresh token

MFA tokens are one-time-use, enforced via a distributed store (Redis or in-memory fallback).

Implemented in services/api-gateway/src/routes/auth.ts at commit 4b572c2.


Property Value
Name elysium_session
HttpOnly true
Secure true
SameSite none
Partitioned true
Max-Age 7 days

Session Flow

  1. User authenticates via signin, MFA verification, or Google OAuth
  2. Server sets elysium_session cookie alongside the JWT response
  3. On subsequent requests, cookie middleware runs before the auth middleware
  4. Cookie middleware extracts and validates the session, populating req.tenantId, req.user.userId, req.user.role, and req.user.email
  5. Session-authenticated users receive null API key scopes (unrestricted access equivalent to admin)

Both mechanisms coexist. The auth middleware checks for cookie-based pre-authentication first. If a valid session cookie is present, JWT/API key validation is skipped.

Implemented in packages/auth/src/cookie-middleware.ts and packages/auth/src/middleware.ts at commit 4b572c2.


Google OAuth

Flow

  1. Client obtains Google OAuth credential via Google Sign-In
  2. Client sends credential to POST /api/public/oauth/google
  3. Server verifies credential via Google client library
  4. If user does not exist, server auto-provisions tenant and user based on email domain
  5. Server issues backend JWT + session cookie

Auto-Provisioning

Google OAuth supports automatic user and tenant creation. Users signing in via Google do not require pre-registration or invite tokens. A new tenant is created per unique email domain.

Implemented in services/api-gateway/src/routes/auth.ts (lines 1066-1266) at commit 4b572c2.

results matching ""

    No results matching ""