Skip to main content

The Auth Law

Authentication across the entire BrokerOS monorepo is powered exclusively by Better Auth. Custom JWT minting, custom session tables, and custom password hashing algorithms are strictly prohibited by system architecture law. Every client (web, mobile, background workers) authenticates through the unified Better Auth server instance mounted in apps/api/src/auth/.

Authentication Flow


1. Backend Implementation (NestJS 11)

The backend integrates @thallesp/nestjs-better-auth with the Better Auth server instance in apps/api/src/auth/.

Route Protection with Role Guards

Endpoints enforce role-based access control using the @Roles() decorator:
Role Security Invariant: The user role is always read server-side from session.user.role. The API must never accept a role parameter from request bodies, headers, or query parameters.

Public Endpoints

Public endpoints (such as incoming webhook receivers or public media endpoints) use the @Public() decorator to bypass authentication:

2. Frontend Implementation (Next.js 16)

The web application uses the official better-auth/react client configured in apps/web/lib/auth-client.ts:

Route Protection via Next.js 16 Proxy

In accordance with Next.js 16 conventions, route protection and workspace redirects are handled in apps/web/proxy.ts. The proxy intercepts requests, verifies session cookies, and redirects unauthenticated users to /login before rendering protected /dashboard workspaces.

3. Mobile Implementation (Expo React Native)

The mobile application integrates @better-auth/expo with expo-secure-store:
  1. Keystore Storage: On login, session tokens are stored inside expo-secure-store, protected by Android Keystore hardware-backed encryption.
  2. Authorization Headers: The token is attached as an Authorization: Bearer <token> header to all API requests and WebSocket handshakes.
  3. Native Background Persistence: The session token is copied to native SharedPreferences via setAuthTokenForBackground. This allows the Kotlin background worker (CallUploadWorker.kt) to upload audio files even when the React Native JavaScript thread is paused or the app is closed.

4. Multi-Factor Authentication (MFA / 2FA)

BrokerOS integrates Better Auth RFC 6238 time-based one-time passwords (TOTP) through the official twoFactor and twoFactorClient plugins.

Architecture & Data Model

  • Database Model: Stored in the dedicated TwoFactor table (packages/prisma/schema.prisma), referencing User.id with cascade deletion. Contains encrypted secrets, hashed recovery codes, verification flags, and temporary lock counters.
  • Server Plugin: Configured in apps/api/src/lib/auth.ts with twoFactor({ issuer: 'BrokerOS' }). Automatically intercepts /sign-in/email, /sign-in/username, and /sign-in/phone-number.
  • Client Plugin: Registered in apps/web/lib/auth-client.ts via twoFactorClient().

Executive Login Challenge Flow

In-App UI Configuration

  • Path: Dashboard -> Admin -> Settings -> Security & Permissions
  • Component: AdminSecuritySettings.tsx
  • Features: Real-time 2FA activation with password confirmation, secret key copy, 6-digit test code verification, single-use recovery backup codes display, and password-authenticated deactivation.

Security Invariants