Auth.js (NextAuth) — Authentication for the Web
You are an expert in Auth.js (formerly NextAuth.js), the authentication library for web frameworks. You help developers add sign-in with 80+ OAuth providers (Google, GitHub, Apple, Discord), email/password, magic links, and WebAuthn to Next.js, SvelteKit, Express, and other frameworks — with session management, JWT/database sessions, role-based access, and middleware protection.
Core Capabilities
Next.js Setup
// auth.ts — Auth.js configuration
import NextAuth from "next-auth";
import Google from "next-auth/providers/google";
import GitHub from "next-auth/providers/github";
import Credentials from "next-auth/providers/credentials";
import { DrizzleAdapter } from "@auth/drizzle-adapter";
import { db } from "./db";
import { verifyPassword } from "./lib/password";
export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: DrizzleAdapter(db),
providers: [
Google({ clientId: process.env.GOOGLE_ID!, clientSecret: process.env.GOOGLE_SECRET! }),
GitHub({ clientId: process.env.GITHUB_ID!, clientSecret: process.env.GITHUB_SECRET! }),
Credentials({
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
authorize: async (credentials) => {
const user = await db.query.users.findFirst({
where: eq(users.email, credentials.email as string),
});
if (!user || !await verifyPassword(credentials.password as string, user.hashedPassword)) {
return null;
}
return { id: user.id, email: user.email, name: user.name, role: user.role };
},
}),
],
callbacks: {
session: ({ session, token }) => ({
...session,
user: { ...session.user, id: token.sub, role: token.role },
}),
jwt: ({ token, user }) => {
if (user) token.role = (user as any).role;
return token;
},
},
pages: {
signIn: "/auth/signin",
error: "/auth/error",
},
});
// app/api/auth/[...nextauth]/route.ts
export { handlers as GET, handlers as POST } from "@/auth";
Protected Routes
// middleware.ts — Protect routes
import { auth } from "./auth";
export default auth((req) => {
const isLoggedIn = !!req.auth;
const isOnDashboard = req.nextUrl.pathname.startsWith("/dashboard");
const isOnAdmin = req.nextUrl.pathname.startsWith("/admin");
if (isOnAdmin && req.auth?.user?.role !== "admin") {
return Response.redirect(new URL("/unauthorized", req.nextUrl));
}
if (isOnDashboard && !isLoggedIn) {
return Response.redirect(new URL("/auth/signin", req.nextUrl));
}
});
export const config = { matcher: ["/dashboard/:path*", "/admin/:path*"] };
React Components
import { auth, signIn, signOut } from "@/auth";
// Server component
async function UserNav() {
const session = await auth();
if (!session?.user) {
return (
<form action={async () => { "use server"; await signIn("google"); }}>
<button>Sign in with Google</button>
</form>
);
}
return (
<div>
<img src={session.user.image!} alt="" className="w-8 h-8 rounded-full" />
<span>{session.user.name}</span>
<form action={async () => { "use server"; await signOut(); }}>
<button>Sign out</button>
</form>
</div>
);
}
// Client component
"use client";
import { useSession } from "next-auth/react";
function ClientProfile() {
const { data: session, status } = useSession();
if (status === "loading") return <Spinner />;
if (!session) return <p>Not signed in</p>;
return <p>Welcome, {session.user.name}!</p>;
}
Installation
npm install next-auth@beta # Auth.js v5 for Next.js
npm install @auth/drizzle-adapter # Database adapter
Best Practices
- 80+ providers — Google, GitHub, Apple, Discord, Slack, etc.; add by importing and configuring
- Database adapters — Drizzle, Prisma, MongoDB, Supabase, Turso; stores users and sessions
- Middleware protection — Auth check at the edge; fast, runs before page renders
- Callbacks — Use
jwt and session callbacks to add custom fields (role, plan, org)
- Server actions —
signIn() and signOut() work as Next.js server actions; no client-side SDK needed
- Edge compatible — Runs on Vercel Edge, Cloudflare Workers; JWT sessions for stateless auth
- CSRF protection — Built-in CSRF token validation; no additional setup needed
- Multi-framework — Works with Next.js, SvelteKit, Express, Qwik; same config pattern
1---2name: authjs3description: You are an expert in Auth.js (formerly NextAuth.js), the authentication library for web frameworks. You help developers add sign-in with 80+ OAuth providers (Google, GitHub, Apple, Discord), email/password, magic links, and WebAuthn to Next.js, SvelteKit, Express, and other frameworks — with session management, JWT/database sessions, role-based access, and middleware protection.4license: Apache-2.05---67# Auth.js (NextAuth) — Authentication for the Web89You are an expert in Auth.js (formerly NextAuth.js), the authentication library for web frameworks. You help developers add sign-in with 80+ OAuth providers (Google, GitHub, Apple, Discord), email/password, magic links, and WebAuthn to Next.js, SvelteKit, Express, and other frameworks — with session management, JWT/database sessions, role-based access, and middleware protection.1011## Core Capabilities1213### Next.js Setup1415```typescript16// auth.ts — Auth.js configuration17import NextAuth from "next-auth";18import Google from "next-auth/providers/google";19import GitHub from "next-auth/providers/github";20import Credentials from "next-auth/providers/credentials";21import { DrizzleAdapter } from "@auth/drizzle-adapter";22import { db } from "./db";23import { verifyPassword } from "./lib/password";2425export const { handlers, auth, signIn, signOut } = NextAuth({26 adapter: DrizzleAdapter(db),27 providers: [28 Google({ clientId: process.env.GOOGLE_ID!, clientSecret: process.env.GOOGLE_SECRET! }),29 GitHub({ clientId: process.env.GITHUB_ID!, clientSecret: process.env.GITHUB_SECRET! }),30 Credentials({31 credentials: {32 email: { label: "Email", type: "email" },33 password: { label: "Password", type: "password" },34 },35 authorize: async (credentials) => {36 const user = await db.query.users.findFirst({37 where: eq(users.email, credentials.email as string),38 });39 if (!user || !await verifyPassword(credentials.password as string, user.hashedPassword)) {40 return null;41 }42 return { id: user.id, email: user.email, name: user.name, role: user.role };43 },44 }),45 ],46 callbacks: {47 session: ({ session, token }) => ({48 ...session,49 user: { ...session.user, id: token.sub, role: token.role },50 }),51 jwt: ({ token, user }) => {52 if (user) token.role = (user as any).role;53 return token;54 },55 },56 pages: {57 signIn: "/auth/signin",58 error: "/auth/error",59 },60});6162// app/api/auth/[...nextauth]/route.ts63export { handlers as GET, handlers as POST } from "@/auth";64```6566### Protected Routes6768```typescript69// middleware.ts — Protect routes70import { auth } from "./auth";7172export default auth((req) => {73 const isLoggedIn = !!req.auth;74 const isOnDashboard = req.nextUrl.pathname.startsWith("/dashboard");75 const isOnAdmin = req.nextUrl.pathname.startsWith("/admin");7677 if (isOnAdmin && req.auth?.user?.role !== "admin") {78 return Response.redirect(new URL("/unauthorized", req.nextUrl));79 }80 if (isOnDashboard && !isLoggedIn) {81 return Response.redirect(new URL("/auth/signin", req.nextUrl));82 }83});8485export const config = { matcher: ["/dashboard/:path*", "/admin/:path*"] };86```8788### React Components8990```tsx91import { auth, signIn, signOut } from "@/auth";9293// Server component94async function UserNav() {95 const session = await auth();9697 if (!session?.user) {98 return (99 <form action={async () => { "use server"; await signIn("google"); }}>100 <button>Sign in with Google</button>101 </form>102 );103 }104105 return (106 <div>107 <img src={session.user.image!} alt="" className="w-8 h-8 rounded-full" />108 <span>{session.user.name}</span>109 <form action={async () => { "use server"; await signOut(); }}>110 <button>Sign out</button>111 </form>112 </div>113 );114}115116// Client component117"use client";118import { useSession } from "next-auth/react";119120function ClientProfile() {121 const { data: session, status } = useSession();122 if (status === "loading") return <Spinner />;123 if (!session) return <p>Not signed in</p>;124 return <p>Welcome, {session.user.name}!</p>;125}126```127128## Installation129130```bash131npm install next-auth@beta # Auth.js v5 for Next.js132npm install @auth/drizzle-adapter # Database adapter133```134135## Best Practices1361371. **80+ providers** — Google, GitHub, Apple, Discord, Slack, etc.; add by importing and configuring1382. **Database adapters** — Drizzle, Prisma, MongoDB, Supabase, Turso; stores users and sessions1393. **Middleware protection** — Auth check at the edge; fast, runs before page renders1404. **Callbacks** — Use `jwt` and `session` callbacks to add custom fields (role, plan, org)1415. **Server actions** — `signIn()` and `signOut()` work as Next.js server actions; no client-side SDK needed1426. **Edge compatible** — Runs on Vercel Edge, Cloudflare Workers; JWT sessions for stateless auth1437. **CSRF protection** — Built-in CSRF token validation; no additional setup needed1448. **Multi-framework** — Works with Next.js, SvelteKit, Express, Qwik; same config pattern