Bookmark

How to Handle Authentication in Next.js 14 App Router

How to Handle Authentication in Next.js 14 App Route

Authentication has always been one of the trickiest parts of building web applications. With the introduction of the App Router in Next.js, the paradigm shifted from client-side fetching and `getServerSideProps` to Server Components and Middleware. Handling authentication correctly in Next.js 14 requires a solid understanding of these new concepts.

In this comprehensive guide, I will share the exact approach I use to implement secure, robust authentication in Next.js 14 using Auth.js (formerly NextAuth.js), complete with code examples from real-world SaaS applications I've built.

1. The Shift to Server-First Authentication

In older Next.js versions (the Pages router), we relied heavily on client-side hooks like useSession() and protected pages using Higher-Order Components (HOCs) or API routes. Next.js 14 encourages a server-first approach.

Why is this better? Security and performance. When you authenticate a user on the server before the page even renders, you eliminate the "loading flash" where a user sees a protected layout for a split second before being redirected. Furthermore, sensitive tokens never need to reach the client.

2. Setting up Auth.js (NextAuth v5)

Auth.js v5 is designed explicitly for the App Router and Server Components. Let's start by installing the beta version that supports next.js 14 optimally.

npm install next-auth@beta

Next, we need to create our auth configuration. Instead of putting this deep in an API route, we create a central auth.ts file in the root of our project.

// auth.ts
import NextAuth from "next-auth"
import GitHub from "next-auth/providers/github"

export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [GitHub],
  pages: {
    signIn: '/login',
  },
  callbacks: {
    authorized({ auth, request: { nextUrl } }) {
      const isLoggedIn = !!auth?.user;
      const isOnDashboard = nextUrl.pathname.startsWith('/dashboard');
      if (isOnDashboard) {
        if (isLoggedIn) return true;
        return false; // Redirect unauthenticated users to login page
      } else if (isLoggedIn) {
        return Response.redirect(new URL('/dashboard', nextUrl));
      }
      return true;
    },
  },
})

3. The API Route Handler

We still need an API route for Auth.js to handle OAuth callbacks and session management commands. Create a file at app/api/auth/[...nextauth]/route.ts:

// app/api/auth/[...nextauth]/route.ts
import { handlers } from "@/auth"
export const { GET, POST } = handlers
My Experience: In a recent project, I forgot to export POST and spent hours debugging why role-based sign-ins were failing. Next.js App Router strictly requires exporting the specific HTTP methods you intend to support!

4. Protecting Routes with Middleware

Middleware is the most powerful way to protect routes in Next.js 14 because it runs on the Edge before a request is completed. By exporting our auth configuration into `middleware.ts`, we can protect entire directories instantly.

// middleware.ts
import { auth } from "@/auth"

export default auth((req) => {
  // Our authorized callback handles the logic
})

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
}

5. Accessing Session Data in Server Components

Reading the user's session in a Server Component is now incredibly elegant. You simply await the auth() function. No context providers, no loading states.

// app/dashboard/page.tsx
import { auth } from "@/auth"

export default async function Dashboard() {
  const session = await auth()

  return (
    <div>
      <h1>Welcome back, {session?.user?.name}</h1>
      <p>Your email is: {session?.user?.email}</p>
    </div>
  )
}

Authentication in Next.js 14 App Router represents a massive step forward in developer experience and application security. By leveraging React Server Components and Next.js Middleware with Auth.js v5, you can build auth flows that are fast, secure, and require significantly less boilerplate than before.

In the next article, I'll dive into how you can connect this setup to a PostgreSQL database using Prisma to store user accounts permanently.

Post a Comment

Post a Comment