Table of Contents
- Introduction
- What is NextAuth.js?
- Setting Up NextAuth.js in a Next.js App
- Configuring Providers in NextAuth.js
- Using Session Management in NextAuth.js
- Protecting Routes with Middleware
- Customizing Authentication Flow
- Handling Callback URLs and Redirects
- NextAuth.js Security Best Practices
- Advanced Authentication: Role-Based Access Control
- Conclusion
1. Introduction
Authentication is a critical part of any web application. In Next.js, integrating authentication can be streamlined with the use of NextAuth.js, a flexible and easy-to-use authentication library designed to work seamlessly with Next.js.
This module will walk you through setting up NextAuth.js, managing sessions, and protecting your routes using Next.js middleware. You will also learn how to customize the authentication flow, handle security, and implement role-based access control.
2. What is NextAuth.js?
NextAuth.js is a complete authentication solution for Next.js applications. It supports multiple authentication providers (like Google, GitHub, and email/password) and offers features such as:
- Session management
- Role-based authentication
- CSRF protection
- JWT-based sessions (or database-based sessions)
NextAuth.js eliminates the need to write custom authentication code, making it easier to integrate authentication into your app quickly. It is highly customizable and can be used with a variety of authentication mechanisms.
3. Setting Up NextAuth.js in a Next.js App
To get started, you need to install NextAuth.js:
bashCopyEditnpm install next-auth
Once installed, you can create the NextAuth.js configuration file. This configuration defines how authentication will work, including providers and session options.
Steps to set up NextAuth.js:
- Create the API route for authentication: Inside the
pages/api/auth
directory, create a[...nextauth].ts
or[...nextauth].js
file to handle authentication.
tsxCopyEdit// pages/api/auth/[...nextauth].ts
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
secret: process.env.NEXTAUTH_SECRET, // Optional for added security
});
In this example, the app uses Google as an authentication provider. You’ll need to set up credentials from the Google Developer Console for this to work.
- Configure environment variables:
- Add your Google OAuth credentials (
GOOGLE_CLIENT_ID
,GOOGLE_CLIENT_SECRET
). - Optionally, set a NextAuth secret (
NEXTAUTH_SECRET
) to secure the session and JWT tokens.
- Add your Google OAuth credentials (
4. Configuring Providers in NextAuth.js
NextAuth.js supports various authentication providers out of the box, including:
- OAuth providers (Google, Facebook, GitHub, Twitter)
- Credentials provider (email/password authentication)
- JWT provider (for custom authentication systems)
Here’s an example of adding multiple authentication providers:
tsxCopyEdit// pages/api/auth/[...nextauth].ts
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import GitHubProvider from "next-auth/providers/github";
import CredentialsProvider from "next-auth/providers/credentials";
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
GitHubProvider({
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
}),
CredentialsProvider({
name: "Credentials",
credentials: {
username: { label: "Username", type: "text" },
password: { label: "Password", type: "password" },
},
authorize(credentials) {
// Custom logic to authorize user
return { id: 1, name: "John Doe" };
},
}),
],
session: {
strategy: "jwt",
},
secret: process.env.NEXTAUTH_SECRET,
});
In this configuration:
- Google and GitHub are used as OAuth providers.
- A custom credentials provider is set up for email/password authentication.
5. Using Session Management in NextAuth.js
NextAuth.js automatically manages sessions once the user logs in. It stores the session data in either a JWT token or a database (depending on your configuration).
To access the session data in your components or pages, you can use the useSession
hook from NextAuth.js:
tsxCopyEdit// Example in a React component
import { useSession, signIn, signOut } from "next-auth/react";
export default function Home() {
const { data: session } = useSession();
if (session) {
return (
<div>
<h1>Welcome, {session.user.name}</h1>
<button onClick={() => signOut()}>Sign out</button>
</div>
);
}
return (
<div>
<h1>Not signed in</h1>
<button onClick={() => signIn("google")}>Sign in with Google</button>
</div>
);
}
Here, useSession
is used to check if the user is authenticated. If the session is valid, the user’s name is displayed, and they can log out. Otherwise, a sign-in button is shown.
6. Protecting Routes with Middleware
You can protect routes in Next.js using middleware to ensure that only authenticated users can access certain pages. This is particularly useful for handling private routes like dashboards or account settings.
Next.js 12+ introduced middleware, allowing you to write server-side logic before a request is processed.
Example of protecting a route with middleware:
tsxCopyEdit// middleware.ts
import { NextResponse } from 'next/server';
import { getToken } from 'next-auth/jwt';
export async function middleware(req) {
const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET });
if (!token) {
return NextResponse.redirect(new URL('/auth/signin', req.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/dashboard/*', '/profile/*'], // Protect these routes
};
In this middleware, getToken
is used to check if the user has a valid session. If not, they are redirected to the sign-in page.
7. Customizing Authentication Flow
NextAuth.js allows you to customize the authentication flow using callbacks. For example, you can modify the user object after they sign in, store custom user data in the session, or trigger additional actions during sign-in.
Example of a custom sign-in callback:
tsxCopyEdit// pages/api/auth/[...nextauth].ts
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
callbacks: {
async jwt({ token, user }) {
if (user) {
token.id = user.id;
token.email = user.email;
}
return token;
},
async session({ session, token }) {
session.id = token.id;
session.email = token.email;
return session;
},
},
});
In this example, the JWT and session callbacks are used to include custom fields (like id
and email
) in the session.
8. Handling Callback URLs and Redirects
You can configure callback URLs to control where users are redirected after they sign in or out.
tsxCopyEdit// pages/api/auth/[...nextauth].ts
export default NextAuth({
providers: [
// Providers setup
],
pages: {
signIn: '/auth/signin',
error: '/auth/error', // Optional custom error page
callbackUrl: '/dashboard',
},
});
With the callbackUrl
, you can specify where users should be redirected after successfully signing in.
9. NextAuth.js Security Best Practices
- Use HTTPS: Always use HTTPS in production to prevent session hijacking and man-in-the-middle attacks.
- Set a strong secret: Ensure the
NEXTAUTH_SECRET
is a long and secure value. - Session expiration: Configure session expiration appropriately to reduce the risk of stale sessions.
- Rate limiting: Consider implementing rate-limiting to protect your authentication endpoints from brute force attacks.
10. Advanced Authentication: Role-Based Access Control
To implement role-based access control (RBAC), you can store user roles in your database and add logic to your Next.js app to enforce role-based permissions.
tsxCopyEdit// Example of RBAC middleware in Next.js
export async function middleware(req) {
const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET });
if (token && token.role === 'admin') {
return NextResponse.next();
}
return NextResponse.redirect(new URL('/auth/unauthorized', req.url));
}
In this example, the middleware checks if the user’s role is admin
. If not, they are redirected to an unauthorized page.
11. Conclusion
NextAuth.js simplifies authentication in Next.js applications, providing a robust solution with a range of providers, session management, and customization options. By integrating middleware, you can protect routes, implement role-based access, and ensure your app is secure.
As your app grows, NextAuth.js allows you to scale your authentication system, adding more features and customizations as needed.