Master Code
On The Go

Learn. Practice. Build.

Home › How-To › Next.js Authentication

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.

1

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
2

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;
        }
    }
});
3

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.

4

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.

5

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>;
}
6

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.

7

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

🛡️ 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.

❓ 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.

🎯 What's Next?

← All How-To Guides