Authentication with Auth.js (NextAuth v5)
Auth is hard. Don't build it from scratch. Auth.js (the new name for NextAuth) handles OAuth, credentials, sessions, JWTs, and more. Here's how to set it up properly in Next.js 15.
⚠️
NextAuth v4 vs Auth.js v5
If you see tutorials using 'next-auth' with api/auth/[...nextauth]/route.ts, that's v4 (old). Auth.js v5 uses a different setup with auth.ts at the root. This guide covers v5.
Installation
Terminal
bash
1npm install next-auth@betaSetup
src/auth.ts
tsx
1// src/auth.ts2import NextAuth from "next-auth";3import GitHub from "next-auth/providers/github";4import Google from "next-auth/providers/google";56export const { handlers, signIn, signOut, auth } = NextAuth({7providers: [8 GitHub({9 clientId: process.env.GITHUB_ID!,10 clientSecret: process.env.GITHUB_SECRET!,11 }),12 Google({13 clientId: process.env.GOOGLE_ID!,14 clientSecret: process.env.GOOGLE_SECRET!,15 }),16],17});src/app/api/auth/[...nextauth]/route.ts
tsx
1// src/app/api/auth/[...nextauth]/route.ts2import { handlers } from "@/auth";34export const { GET, POST } = handlers;Protecting Pages
src/app/dashboard/page.tsx
tsx
1// src/app/dashboard/page.tsx2import { auth } from "@/auth";3import { redirect } from "next/navigation";45export default async function DashboardPage() {6const session = await auth();78if (!session) {9 redirect("/login");10}1112return (13 <div>14 <h1>Welcome, {session.user?.name}</h1>15 <img src={session.user?.image ?? ""} alt="Avatar" />16 </div>17);18}Sign In / Sign Out Buttons
src/components/AuthButtons.tsx
tsx
1// src/components/AuthButtons.tsx2import { signIn, signOut, auth } from "@/auth";34export async function SignInButton() {5const session = await auth();67if (session) {8 return (9 <form action={async () => {10 "use server";11 await signOut();12 }}>13 <button type="submit">Sign Out</button>14 </form>15 );16}1718return (19 <form action={async () => {20 "use server";21 await signIn("github");22 }}>23 <button type="submit">Sign in with GitHub</button>24 </form>25);26}🚀
Middleware for auth
For protecting multiple routes, combine Auth.js with middleware. Check the session in middleware and redirect unauthenticated users. This way you don't need auth checks in every individual page.