Next.js Guide
Next.js Authentication with Auth.js
Add secure login to your Next.js app — Google, GitHub, email/password, and protected routes. All handled by Auth.js.
Quick answer: Install next-auth@beta, create an auth.ts config with your providers, add the catch-all route at app/api/auth/[...nextauth]/route.ts, and use auth() to read the session anywhere.
Install Auth.js
npm install next-auth@beta
Auth.js v5 is the version that works with the App Router. Add the required environment variables:
# .env.local
AUTH_SECRET=your-secret-here
AUTH_GITHUB_ID=your-github-client-id
AUTH_GITHUB_SECRET=your-github-client-secret
Generate a secret with:
npx auth secret
Create the Auth Config
Create auth.ts at your project root:
import NextAuth from 'next-auth';
import GitHub from 'next-auth/providers/github';
import Google from 'next-auth/providers/google';
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [GitHub, Google],
pages: {
signIn: '/login'
},
callbacks: {
async session({ session, token }) {
if (token.sub) session.user.id = token.sub;
return session;
}
}
});
Add the Route Handler
Create app/api/auth/[...nextauth]/route.ts:
import { handlers } from '@/auth';
export const { GET, POST } = handlers;
This single file handles every OAuth callback, sign-in, sign-out, and session endpoint.
Add Sign-In and Sign-Out Buttons
import { signIn, signOut } from '@/auth';
// Sign-in button (Server Component)
export function SignIn() {
return (
<form action={async () => {
'use server';
await signIn('github');
}}>
<button type="submit">Sign in with GitHub</button>
</form>
);
}
// Sign-out button
export function SignOut() {
return (
<form action={async () => {
'use server';
await signOut();
}}>
<button type="submit">Sign out</button>
</form>
);
}
Server Actions let you handle auth without writing client-side fetch calls.
Read the Session
In any Server Component:
import { auth } from '@/auth';
export default async function Dashboard() {
const session = await auth();
if (!session) {
return <p>Not logged in</p>;
}
return <h1>Welcome, {session.user?.name}</h1>;
}
In a Client Component:
'use client';
import { useSession } from 'next-auth/react';
export function Profile() {
const { data: session, status } = useSession();
if (status === 'loading') return <p>Loading...</p>;
if (!session) return <p>Not logged in</p>;
return <p>{session.user?.email}</p>;
}
Protect Routes with Middleware
Create middleware.ts at your project root:
import { auth } from '@/auth';
import { NextResponse } from 'next/server';
export default auth((req) => {
const isLoggedIn = !!req.auth;
const isOnDashboard = req.nextUrl.pathname.startsWith('/dashboard');
if (isOnDashboard && !isLoggedIn) {
return NextResponse.redirect(new URL('/login', req.url));
}
return NextResponse.next();
});
export const config = {
matcher: ['/dashboard/:path*', '/admin/:path*']
};
💡 Note: In Next.js 16, middleware.ts was renamed to proxy.ts. Both names work in v15.
Wrap the Session Provider
For client-side useSession(), wrap your app in app/layout.tsx:
import { SessionProvider } from 'next-auth/react';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<SessionProvider>{children}</SessionProvider>
</body>
</html>
);
}
🎯 Auth Patterns You'll Use
- Server-side session check —
const session = await auth()in any Server Component - Client-side session check —
useSession()for interactive UI - Route protection — middleware with a matcher for admin routes
- Protected API routes —
const session = await auth(); if (!session) return new Response('Unauthorized', { status: 401 }) - Role-based access — add a role to the session and check it in middleware
🛡️ Security Best Practices
Never implement auth yourself unless you understand CSRF, session fixation, password hashing (bcrypt/argon2), OAuth flows, and rate limiting. Auth.js handles all of it.
- Always use HTTPS in production — cookies need the Secure flag
- Use a strong
AUTH_SECRET— at least 32 random bytes - Enable email verification for email/password auth
- Rate-limit sign-in attempts to prevent brute force
- Never log sensitive data (tokens, passwords)
- Use short session expiry + refresh tokens for long-lived sessions
- Store secrets in environment variables, never in code
❓ Frequently Asked Questions
What is the best way to add auth to Next.js?
;Auth.js (formerly NextAuth.js) — it supports 80+ OAuth providers, email/password, and the App Router out of the box.
Should I build my own auth?
No. Use Auth.js unless you have very specific needs. Building auth means handling password hashing, CSRF, OAuth flows, and edge cases.
How do I protect a route?
Use middleware with a matcher, or check await auth() in the Server Component and redirect.
Can I use a database with Auth.js?
;Yes — Prisma, Drizzle, or any adapter. Or use JWT sessions with no database.
Does Auth.js work with App Router?
Yes. Auth.js v5 is designed for the App Router with Server Components, Server Actions, and middleware.