To secure NextAuth + Prisma integration, you need to: (1) use the PrismaAdapter for database session storage, (2) include user.id in the session callback for database queries, (3) check auth() in all API routes and Server Components, (4) set a strong NEXTAUTH_SECRET (32+ characters), and (5) properly configure OAuth callback URLs. This blueprint ensures sessions are securely stored and user identity is verified server-side.
TL;DR
NextAuth with Prisma adapter stores sessions in your database. Use the session callback to include user ID in the session, protect API routes with getServerSession, and configure NEXTAUTH_SECRET properly. Database sessions are more secure than JWTs for sensitive apps.
Auth Configuration NextAuth Prisma
import NextAuth from 'next-auth'
import { PrismaAdapter } from '@auth/prisma-adapter'
import { prisma } from '@/lib/prisma'
import GitHub from 'next-auth/providers/github'
export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GitHub({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
],
callbacks: {
session: ({ session, user }) => ({
...session,
user: {
...session.user,
id: user.id, // Include user ID in session
},
}),
},
})
Protected API Route
import { auth } from '@/lib/auth'
import { NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'
export async function POST(req: Request) {
const session = await auth()
if (!session?.user?.id) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const body = await req.json()
const post = await prisma.post.create({
data: {
title: body.title,
authorId: session.user.id, // Verified user ID from session
},
})
return NextResponse.json(post)
}
export async function GET() {
const session = await auth()
if (!session?.user?.id) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const posts = await prisma.post.findMany({
where: { authorId: session.user.id },
})
return NextResponse.json(posts)
}
Protected Server Component
import { auth } from '@/lib/auth'
import { redirect } from 'next/navigation'
import { prisma } from '@/lib/prisma'
export default async function Dashboard() {
const session = await auth()
if (!session?.user?.id) {
redirect('/api/auth/signin')
}
const posts = await prisma.post.findMany({
where: { authorId: session.user.id },
})
return (
<div>
<h1>Welcome, {session.user.name}</h1>
{posts.map(post => <div key={post.id}>{post.title}</div>)}
</div>
)
}
Always include user ID in session callback. By default, NextAuth sessions don't include the database user ID. Add it in the callback to use for database queries.
Security Checklist
Pre-Launch Checklist
NEXTAUTH_SECRET set (32+ chars)
Session callback includes user ID
API routes check auth()
OAuth callback URLs configured
Database connection secured
Related Integration Stacks
Clerk + Next.js Managed Auth Auth0 + Next.js Alternative Redis Session Management