Documentation

Authentication

Secure authentication with NextAuth v5, OAuth providers, and role-based access control (RBAC).

Overview

The AI SaaS Starter Kit uses NextAuth.js (Auth.js v5) for authentication. It supports multiple authentication methods including OAuth providers and email/password credentials with built-in RBAC.

Authentication Methods

1. OAuth Providers

Pre-configured OAuth providers:

  • Google - Sign in with Google account
  • GitHub - Sign in with GitHub account

Configuration

Set up OAuth providers in your .env file:

# Google OAuth
GOOGLE_CLIENT_ID="your-google-client-id"
GOOGLE_CLIENT_SECRET="your-google-client-secret"

# GitHub OAuth
GITHUB_ID="your-github-client-id"
GITHUB_SECRET="your-github-client-secret"

Google OAuth Setup

  1. Go to Google Cloud Console
  2. Create a new project or select existing one
  3. Navigate to APIs & Services → Credentials
  4. Click "Create Credentials" → "OAuth client ID"
  5. Select "Web application"
  6. Add authorized redirect URI:
    • Development: http://localhost:3000/api/auth/callback/google
    • Production: https://yourdomain.com/api/auth/callback/google
  7. Copy Client ID and Client Secret to .env

GitHub OAuth Setup

  1. Go to GitHub Settings → Developer settings → OAuth Apps
  2. Click "New OAuth App"
  3. Fill in application details:
    • Homepage URL: http://localhost:3000
    • Authorization callback URL: http://localhost:3000/api/auth/callback/github
  4. Click "Register application"
  5. Generate a new client secret
  6. Copy Client ID and Client Secret to .env

2. Email/Password (Credentials)

Users can register and sign in with email and password.

Password Security

  • Passwords hashed with bcrypt (10 rounds)
  • Minimum 8 characters required
  • Stored securely in database

Registration Flow

// POST /api/auth/register
{
  "name": "John Doe",
  "email": "john@example.com",
  "password": "SecurePassword123"
}

// Response
{
  "message": "User registered successfully",
  "user": {
    "id": "clx123...",
    "name": "John Doe",
    "email": "john@example.com"
  }
}

Role-Based Access Control (RBAC)

The application implements a comprehensive RBAC system with three default roles:

Default Roles

USER

Standard user role with basic permissions

  • • Access to dashboard
  • • Manage own profile
  • • Use AI features (with credits)
  • • View own subscription

ADMIN

Administrative role with elevated permissions

  • • All USER permissions
  • • Manage users and subscriptions
  • • View analytics dashboard
  • • Manage blog posts
  • • Process refunds

SUPER_ADMIN

Full system access with all permissions

  • • All ADMIN permissions
  • • Assign/remove roles
  • • System configuration
  • • Database management
  • • Delete users

Assigning Roles

Roles can be assigned via:

1. Prisma Studio

# Open Prisma Studio
npx prisma studio

# Navigate to UserRole table
# Create new record with userId and roleId

2. SQL Query

-- Assign SUPER_ADMIN role
INSERT INTO "UserRole" ("userId", "roleId", "assignedAt")
VALUES (
  'user-id-here',
  (SELECT id FROM "Role" WHERE name = 'SUPER_ADMIN'),
  NOW()
);

3. API Endpoint (SUPER_ADMIN only)

// POST /api/users/{userId}/roles
{
  "roleId": "role-id-here"
}

Session Management

JWT Sessions

NextAuth uses JWT (JSON Web Tokens) for session management:

  • Stateless authentication
  • No database queries on every request
  • Automatic token rotation
  • Secure httpOnly cookies

Session Configuration

// src/lib/auth.ts
export const authOptions = {
  session: {
    strategy: "jwt",
    maxAge: 30 * 24 * 60 * 60, // 30 days
  },
  // ...
}

Accessing Session

Server Components

import { auth } from "@/lib/auth";

export default async function Page() {
  const session = await auth();

  if (!session) {
    return <div>Not authenticated</div>;
  }

  return <div>Welcome, {session.user.name}!</div>;
}

Client Components

"use client";
import { useSession } from "next-auth/react";

export default function ClientComponent() {
  const { data: session, status } = useSession();

  if (status === "loading") return <div>Loading...</div>;
  if (!session) return <div>Not authenticated</div>;

  return <div>Welcome, {session.user.name}!</div>;
}

Protected Routes

Proxy Protection

Protect routes using Next.js proxy (proxy.ts):

export { auth as proxy } from "@/lib/auth";

export const config = {
  matcher: [
    "/dashboard/:path*",
    "/admin/:path*",
    "/api/users/:path*",
  ],
};

Server-Side Protection

import { auth } from "@/lib/auth";
import { redirect } from "next/navigation";

export default async function ProtectedPage() {
  const session = await auth();

  if (!session) {
    redirect("/auth/signin");
  }

  // Page content
}

Role-Based Protection

import { auth } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { redirect } from "next/navigation";

export default async function AdminPage() {
  const session = await auth();

  if (!session) {
    redirect("/auth/signin");
  }

  // Check if user is admin
  const userRoles = await prisma.userRole.findMany({
    where: { userId: session.user.id },
    include: { role: true },
  });

  const isAdmin = userRoles.some(
    (ur: { role: { name: string } }) => ur.role.name === "ADMIN" || ur.role.name === "SUPER_ADMIN"
  );

  if (!isAdmin) {
    redirect("/dashboard");
  }

  // Admin page content
}

User Registration Flow

Default Credits

New users receive 100 free credits upon registration:

const user = await prisma.user.create({
  data: {
    name,
    email,
    password: hashedPassword,
    credits: 100, // Free credits
    emailVerified: new Date(),
  },
});

Default Role Assignment

New users automatically receive the USER role:

const userRole = await prisma.role.findUnique({
  where: { name: "USER" },
});

await prisma.userRole.create({
  data: {
    userId: user.id,
    roleId: userRole.id,
  },
});

Security Best Practices

Environment Variables

  • Never commit .env files to version control
  • Use strong, random NEXTAUTH_SECRET (32+ characters)
  • Rotate secrets regularly

Password Security

  • Minimum 8 characters enforced
  • Bcrypt hashing with 10 rounds
  • Consider adding password complexity requirements
  • Implement password reset functionality

OAuth Security

  • Use HTTPS in production
  • Verify redirect URIs match exactly
  • Keep client secrets secure
  • Enable 2FA on provider accounts

Session Security

  • httpOnly cookies prevent XSS attacks
  • Secure flag in production (HTTPS only)
  • SameSite attribute prevents CSRF
  • Regular session rotation

Troubleshooting

OAuth Sign-In Failed

  • Verify client ID and secret are correct
  • Check redirect URIs match exactly
  • Ensure OAuth app is enabled in provider dashboard
  • Check NEXTAUTH_URL is set correctly

Session Not Persisting

  • Verify NEXTAUTH_SECRET is set
  • Check cookies are enabled in browser
  • Ensure domain matches in production
  • Clear browser cookies and try again

Role Permissions Not Working

  • Verify user has correct role assigned in database
  • Check role name matches exactly (case-sensitive)
  • Clear session and sign in again
  • Verify role checking logic is correct

API Reference

See the API Documentation for complete authentication endpoints:

  • POST /api/auth/register - Register new user
  • POST /api/auth/signin - Sign in
  • POST /api/auth/signout - Sign out
  • GET /api/auth/session - Get current session