Skip to main content
Chapter 5 Authentication and Middleware

Authentication with Auth.js (NextAuth.js)

26 min read Lesson 17 / 28

Setting Up Auth.js in Next.js 15

Auth.js (formerly NextAuth.js v5) is the standard authentication library for Next.js. It supports OAuth providers (Google, GitHub, Discord), email/password credentials, and magic links with minimal configuration.

Installation

npm install next-auth@beta
npx auth secret  # Generates NEXTAUTH_SECRET in .env.local

Configuration

// auth.ts (root of project)
import NextAuth from 'next-auth';
import GitHub from 'next-auth/providers/github';
import Google from 'next-auth/providers/google';
import Credentials from 'next-auth/providers/credentials';
import { db } from '@/lib/db';
import bcrypt from 'bcryptjs';

export const { handlers, auth, signIn, signOut } = NextAuth({
    providers: [
        GitHub({
            clientId: process.env.GITHUB_ID!,
            clientSecret: process.env.GITHUB_SECRET!,
        }),
        Google({
            clientId: process.env.GOOGLE_CLIENT_ID!,
            clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
        }),
        Credentials({
            credentials: {
                email: { label: 'Email', type: 'email' },
                password: { label: 'Password', type: 'password' },
            },
            async authorize(credentials) {
                if (!credentials?.email || !credentials?.password) {
                    return null;
                }

                const user = await db.user.findUnique({
                    where: { email: credentials.email as string },
                });

                if (!user || !user.password) return null;

                const passwordMatch = await bcrypt.compare(
                    credentials.password as string,
                    user.password
                );

                return passwordMatch ? user : null;
            },
        }),
    ],
    callbacks: {
        async session({ session, token }) {
            if (token.sub) {
                session.user.id = token.sub;
                session.user.role = token.role as string;
            }
            return session;
        },
        async jwt({ token, user }) {
            if (user) {
                token.role = user.role;
            }
            return token;
        },
    },
    pages: {
        signIn: '/login',
        error: '/auth/error',
    },
});

Route Handler

// app/api/auth/[...nextauth]/route.ts
import { handlers } from '@/auth';
export const { GET, POST } = handlers;

Sign In and Out Server Actions

// app/actions/auth.ts
'use server';

import { signIn, signOut } from '@/auth';

export async function signInWithGitHub() {
    await signIn('github', { redirectTo: '/dashboard' });
}

export async function signOutUser() {
    await signOut({ redirectTo: '/' });
}
// components/auth-buttons.tsx
import { signInWithGitHub, signOutUser } from '@/actions/auth';

export function SignInButton() {
    return (
        <form action={signInWithGitHub}>
            <button type="submit" className="flex items-center gap-2 px-4 py-2 bg-gray-900 text-white rounded-lg">
                Sign in with GitHub
            </button>
        </form>
    );
}