Docs
Auth Flow

Auth Flow

End-to-end explanation of the authentication flow

Overview

The authentication layer is powered by NextAuth.js with a custom Kysely adapter. It handles Google OAuth sign-in, builds secure JWT-based sessions, and keeps the current user cached for server components. Business logic lives in services/auth, which coordinates repositories (raw SQL via Kysely), OAuth clients, and downstream features such as automatic personal project creation.

Main Libraries/Services:

  • NextAuth.js – Manages OAuth redirects, JWT/session callbacks, and session cookies.
  • Kysely + raw SQL repositories – Persist users, accounts, sessions, and tokens in PostgreSQL.
  • services/auth/* – Orchestrates registration, provider linking, session handling, verification, and platform-admin checks.
  • lib/session.ts – Provides request-scoped cached helpers (getSession, getCurrentUser, getCurrentUserId).
  • clients/auth – Wraps external OAuth providers for token exchange and profile retrieval.

File Map

  • auth.ts – NextAuth handler; configures providers, callbacks, events, and exposes the auth() helper.
  • config/auth.ts – Defines Google OAuth provider credentials and shared NextAuth options.
  • lib/adapters/kysely-adapter.ts – Custom NextAuth adapter backed by Kysely repositories.
  • lib/session.ts – Caches server-side session lookups per request to avoid redundant I/O.
  • services/auth/session.ts – Implements JWT/session callbacks and exposes helpers to validate, refresh, and destroy sessions.
  • services/auth/providers.ts – Handles OAuth callbacks, account linking, and provider metadata.
  • services/auth/registration.ts – Creates users, personal projects, and project memberships during onboarding.
  • services/auth/user.ts – User CRUD, profile updates, and activity/statistics queries.
  • services/auth/verification.ts – Placeholder service for verification and password reset workflows.
  • services/auth/platform-admin.ts – Determines platform-admin/owner access based on project roles.
  • repositories/auth/* – Raw SQL queries (via Kysely) for users, accounts, sessions, verification tokens, and roles.

Step-by-Step Flow

OAuth Sign-In (Google)

  1. The client calls signIn("google"); NextAuth uses auth.ts/config/auth.ts to redirect to Google with PKCE + state.
  2. After Google calls back, NextAuth invokes ProviderService.handleOAuthCallback() to exchange the code for tokens through clients/auth.
  3. RegistrationService.handleOAuthRegistration() ensures a user record exists, using repositories plus projectService.createPersonalProject() to seed a personal workspace with OWNER membership.
  4. Provider accounts are stored with createAccount/linkProviderAccount, so future sign-ins reuse the same user.

Session & JWT Callbacks

  1. During sign-in, SessionManagementService.handleJWTCallback() enriches the JWT with sub, name, email, and picture.
  2. When a session is read, handleSessionCallback() mirrors token data back into the session payload, preserving expires.
  3. If trigger === "update", the service refetches the latest user via userService.getUserById() to keep session data in sync after profile edits.
  4. SessionService can create, validate, refresh, or revoke database-backed sessions for other features (e.g., admin dashboards).

Session Access in Server Components

  1. auth.ts calls setNextAuthConfig() so lib/session.ts can reuse the NextAuth options without circular imports.
  2. getSession, getCurrentUser, and getCurrentUserId are wrapped with React’s cache() to dedupe work within a request.
  3. Server components and API routes import these helpers to guard routes or fetch the current user without repeated database calls.

Project Bootstrapping & Admin Detection

  1. The NextAuth createUser event triggers projectService.createPersonalProject() so every new account has an OWNER project.
  2. RegistrationService reuses the same logic for invitation acceptance to maintain consistent ownership rules.
  3. SessionManagementService.isAdmin() relies on platform-admin.ts to determine whether the authenticated user owns or administers any project and unlock platform-level actions accordingly.

Data Flow Diagram

flowchart TD
  A[User clicks Sign in] --> B[NextAuth handler (auth.ts)]
  B --> C[services/auth/providers]
  C --> D[registrationService + projectService]
  D --> E[repositories/auth (Kysely + SQL)]
  E --> F[(PostgreSQL)]
  F --> G[SessionManagementService callbacks]
  G --> H[lib/session cached helpers]
  H --> I[Server components & API routes]

Dependencies & Contracts

  • IAuthUser – Canonical user object returned by auth services and stored in JWT/session data.
  • IAuthSession – Session payload emitted by SessionService.
  • IProviderAuthResult – Standard success/error contract for OAuth callbacks and account linking.
  • IUserRegistrationData – Input required when onboarding users via email or provider flows.
  • ISessionValidationResult – Outcome of validating session tokens (valid flag, user, optional error metadata).

Known Limitations

  • Email/password and magic-link flows are not implemented; VerificationService still stores tokens in memory.
  • AuthService.signInWithProvider() contains a TODO to coordinate provider callbacks through a single helper.
  • The legacy Prisma seed script still exists; seeding and migrations must be rewritten around Kysely SQL files.

Notes & TODOs

  • Implement persistent verification-token storage using the auth repositories.
  • Replace the Prisma-based seed pipeline with a Kysely-driven seeding script.
  • Extend RegistrationService once verification storage is ready to support magic-link or other passwordless flows.

Auth Flow – SaaS Starter