Auth.js (NextAuth v5)
Setup, providers, session strategies, adapters.
Auth.js (formerly NextAuth.js) is the most-installed auth library in the Next.js world. v5 cleaned up the API, dropped support for legacy runtimes, and embraced the App Router. In ten minutes you can have email, Google, GitHub, and Discord login working with sessions, CSRF, and cookies all handled for you.
Install & secrets
pnpm add next-auth@beta
npx auth secret # writes AUTH_SECRET to .env.localEvery provider also needs its own client ID and secret in .env.local:
AUTH_SECRET=your-generated-secret
AUTH_GITHUB_ID=Iv1.xxx
AUTH_GITHUB_SECRET=xxx
AUTH_GOOGLE_ID=xxx.apps.googleusercontent.com
AUTH_GOOGLE_SECRET=xxxThe auth.ts hub
One file exports everything: the handlers for the route, the auth() function to read the session on the server, and signIn/signOut for client/server actions.
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
import Google from "next-auth/providers/google";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { prisma } from "@/server/db";
export const { handlers, signIn, signOut, auth } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [GitHub, Google],
session: { strategy: "database" },
callbacks: {
session({ session, user }) {
session.user.id = user.id;
return session;
},
},
});Wire up the route handler
export { GET, POST } from "@/auth/handlers";
// Or, if you exported handlers from auth.ts:
// export { GET, POST } from "@/auth";Session strategies: JWT vs database
- JWT (default): session lives entirely in a signed cookie. No DB lookup per request. You cannot easily revoke. Great for edge runtimes.
- Database: session row stored via an adapter. Requires a DB call per request but is revocable and trivially extensible. Pairs naturally with Prisma/Drizzle.
Reading the session in a Server Component
import { auth } from "@/auth";
import { redirect } from "next/navigation";
export default async function Dashboard() {
const session = await auth();
if (!session) redirect("/login");
return <h1>Hi, {session.user.name}</h1>;
}Protecting groups of routes with proxy.ts
Next.js 16 deprecated the middleware.ts file convention and renamed it to proxy.ts. The behaviour is identical; the file name and the exported function name changed. Put the file at the project root, next to app/.
export { auth as proxy } from "@/auth";
export const config = {
matcher: ["/dashboard/:path*", "/account/:path*"],
};npx @next/codemod@canary middleware-to-proxy . instead of renaming by hand.Sign in & out
// Server Action
"use server";
import { signIn, signOut } from "@/auth";
export async function loginWithGitHub() {
await signIn("github", { redirectTo: "/dashboard" });
}
export async function logout() {
await signOut({ redirectTo: "/" });
}Adapters
Adapters connect Auth.js to a database. The most common in 2026:
@auth/prisma-adapter@auth/drizzle-adapter@auth/supabase-adapter, plus adapters for Mongo, Firebase, Convex, Neon, Turso, etc.
Each adapter expects a few tables (User, Account, Session, VerificationToken). The Prisma adapter has the schema in its README, copy-paste it.
next-auth@latest still resolves to the v4 line, and v5 is only on the beta tag. Everything in this lesson is v5 API, which means you are installing a beta. That is fine for a codebase already on it, and a real consideration for a new one.Quiz
What does `npx auth secret` do?
Recap
- Install
next-auth@beta, runnpx auth secret, add provider env vars. - Centralize everything in
auth.ts: exportshandlers,auth,signIn,signOut. - JWT sessions are stateless and edge-friendly. Database sessions are revocable and richer.
- Adapters wire Auth.js to your DB. Prisma and Drizzle are the most common.
- Protect server components with
await auth()+redirect; protect groups of routes via middleware.