Authentication

How authentication works in SaaS Template.

Overview

Authentication is handled by NextAuth v5 (Auth.js) with JWT sessions. The configuration lives in src/lib/auth/config.ts.

Supported providers

  • Email / password — Bcrypt-hashed passwords stored in the users table
  • Google OAuth — Requires AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET
  • GitHub OAuth — Requires AUTH_GITHUB_ID and AUTH_GITHUB_SECRET

Environment variables

AUTH_SECRET=             # openssl rand -base64 32
AUTH_GOOGLE_ID=
AUTH_GOOGLE_SECRET=
AUTH_GITHUB_ID=
AUTH_GITHUB_SECRET=
NEXTAUTH_URL=http://localhost:3000

Email verification

After registration, users receive a verification email. Unverified users can still log in but see a banner prompting them to verify. The verification token is stored in verification_tokens and expires after 24 hours.

Password reset

The forgot-password flow sends a time-limited reset link to the user's email. Tokens are stored in the users table (resetToken + resetTokenExpiresAt).

Session data

The JWT session includes:

{
  id: string
  email: string
  role: 'USER' | 'ADMIN'
  subscriptionStatus: string | null
  subscriptionPlan: string | null
  emailVerified: boolean
  onboardingCompleted: boolean
}

Protecting routes

Routes are protected in src/middleware.ts. Any path under /dashboard, /billing, /settings, /onboarding, or /referral requires an active session.

To protect an API route manually:

import { auth } from '@/lib/auth'

export async function GET() {
  const session = await auth()
  if (!session?.user?.id) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 })
  }
  // ...
}