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
- Go to Google Cloud Console
- Create a new project or select existing one
- Navigate to APIs & Services → Credentials
- Click "Create Credentials" → "OAuth client ID"
- Select "Web application"
- Add authorized redirect URI:
- Development:
http://localhost:3000/api/auth/callback/google - Production:
https://yourdomain.com/api/auth/callback/google
- Development:
- Copy Client ID and Client Secret to
.env
GitHub OAuth Setup
- Go to GitHub Settings → Developer settings → OAuth Apps
- Click "New OAuth App"
- Fill in application details:
- Homepage URL:
http://localhost:3000 - Authorization callback URL:
http://localhost:3000/api/auth/callback/github
- Homepage URL:
- Click "Register application"
- Generate a new client secret
- 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 roleId2. 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
.envfiles 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_URLis set correctly
Session Not Persisting
- Verify
NEXTAUTH_SECRETis 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 userPOST /api/auth/signin- Sign inPOST /api/auth/signout- Sign outGET /api/auth/session- Get current session