Learning Next.js - Authentication & Authorization
Episode 12 of 24

Learning Next.js - Authentication & Authorization

This episode covers authentication patterns in Next.js, integrating NextAuth.js or Auth.js, protecting routes with middleware and session management, and role-based access control and secure redirects for production applications.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Every application that stores user data needs answers to two questions: who is using the application, and what are they allowed to do. These two things are authentication and authorization.

Episode 12 covers authentication patterns in Next.js, integrating Auth.js (NextAuth.js), protecting routes with middleware and session management, and role-based access control and secure redirects.

Authentication Patterns for Next.js

Architecture Choices

There are several common authentication patterns: session-based, which stores session data in a cookie, JWT, which signs claims in a token, and OAuth, which delegates login to providers like Google or GitHub. The choice depends on the type of application: server-rendered apps suit sessions and cookies, while API-only apps use JWT.

Auth.js as an Integrated Solution

Auth.js (formerly NextAuth.js) is the de facto standard authentication library for Next.js: it supports many OAuth providers, credentials, database sessions, and tight integration with the App Router. Start by installing and configuring the route handler:

Install Auth.js
npm install next-auth@beta

The beta version is Auth.js v5, designed for the App Router. After installing, create the following route handler:

Authentication route handler
import { handlers } from "@/auth"
 
export const { GET, POST } = handlers

The file app/api/auth/[...nextauth]/route.ts above exports GET and POST handlers that manage the entire login and callback flow.

Integrating NextAuth.js and Session Management

Configuring AuthOptions

The center of Auth.js configuration is the auth.ts file at the project root:

Auth.js configuration
import NextAuth from "next-auth"
import Google from "next-auth/providers/google"
 
export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [Google],
  session: { strategy: "jwt" },
})

providers: [Google] enables login with a Google account. The session: { strategy: "jwt" } option stores the session in a JWT — lightweight and suitable without a database.

Reading the Session on the Server

To read the login status in a server component, call the auth() function:

Reading the session in a server component
import { auth } from "@/auth"
 
export default async function Dashboard() {
  const session = await auth()
 
  if (!session) {
    return <p>Silakan login terlebih dahulu.</p>
  }
 
  return <h1>Selamat datang, {session.user.name}</h1>
}

session.user.name displays the logged-in user's name. Checking session at the top of a server component is the basic pattern for protecting pages at the rendering level.

Protecting Routes with Middleware and Sessions

Middleware for Route Protection

To protect many routes at once, use middleware.ts. Middleware runs before the request reaches the page, so it can redirect users who aren't logged in:

Protecting routes with middleware
import { auth } from "@/auth"
 
export default auth((req) => {
  if (!req.auth && req.nextUrl.pathname.startsWith("/dashboard")) {
    const url = req.nextUrl.clone()
    url.pathname = "/login"
    return Response.redirect(url)
  }
})
 
export const config = {
  matcher: ["/dashboard/:path*", "/admin/:path*"],
}

The middleware above redirects unauthenticated users away from /dashboard and /admin to /login. The redirect happens server-side before the page renders, preventing protected content from being sent.

Role-Based Access Control and Secure Redirects

Restricting by Role

Authorization is the layer on top of authentication: once you know who the user is, decide what they may access. Check the role from the session:

Role-based access control
const session = await auth()
const role = session?.user?.role
 
if (role !== "admin") {
  return <p>Anda tidak memiliki akses.</p>
}

The role check in the server component above restricts access to the admin page. For large applications, consider libraries like Permit or Casper for centralized access policies.

Secure Redirects

Avoid open redirects: never copy the destination URL directly from a query parameter without validation. Redirect only to allowed paths. After a successful login, direct users to the page they originally requested, and after logout return them to a public page — all redirect targets must come from a safe list.

Closing

Here's what to take away:

  • Sessions, JWT, and OAuth are the three main authentication patterns.
  • Auth.js unifies many providers with simple configuration.
  • The [...nextauth] route handler manages the whole login flow.
  • The auth() function reads the session in a server component.
  • Middleware protects routes centrally before rendering.
  • RBAC checks roles, and redirects are always validated.

In the next episode, episode 13, we'll discuss API security and data protection — securing route handlers and request validation, CORS and CSRF with secure headers, handling sensitive data and secrets, and rate limiting and abuse prevention. Your application's backend will be fortified.

Learning Next.js - Authentication & Authorization | Learn Next.js