A Practical Guide for Secure Login, JWT Handling, and Protected Routes

Authentication is one of the most important parts of any modern web application. Whether you are building a SaaS product, an admin dashboard, an eCommerce platform, or a custom internal tool, you must ensure that only authorized users can access protected resources.

If you are using Next.js with a separate backend API (such as Node.js with Express, ASP.NET Core, Django, or any REST API), the most common and scalable approach is token-based authentication using JWT (JSON Web Tokens).

In this guide, you will understand how authentication works in a real-world Next.js application, how to connect it with a backend API, how to store tokens securely, and how to protect routes both on the client and server side.

Understanding the Architecture

Before writing any code, let’s understand the typical architecture.

You usually have:

Here’s how the login flow works:

Think of JWT like a digital identity card. Once the server issues it, the frontend carries it with every request to prove identity.

Step 1: Backend API – Login Endpoint

Your backend must expose an authentication endpoint.

Example endpoint:

Code
POST /api/auth/login

Backend logic should:

A typical response looks like this:

Code
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 3600
}

Important security practices:

Step 2: Creating Login in Next.js

In your Next.js application, create a login page.

Inside your login function:

Example logic (simplified explanation):

Where Should You Store the Token?

This is extremely important.

There are three common approaches:

The most secure production-ready approach is:

Use HTTP-only cookies.

Why?

Because JavaScript cannot access HTTP-only cookies, which protects against XSS attacks.

Real-world example:

If you store tokens in localStorage and your site has a cross-site scripting vulnerability, attackers can steal tokens easily. But HTTP-only cookies cannot be accessed by malicious scripts.

Step 3: Setting HTTP-Only Cookie (Recommended)

Instead of storing the token in localStorage, your backend should set the cookie directly.

Example backend behavior:

Code
Set-Cookie: accessToken=xxxxx; HttpOnly; Secure; SameSite=Strict

Now the browser automatically includes this cookie in future requests.

No manual token handling required on the frontend.

This is considered best practice for production applications.

Step 4: Protecting API Requests in Next.js

When calling protected endpoints:

Code
GET /api/user/profile

The browser automatically sends the cookie.

Backend middleware should:

If token is invalid, return 401 Unauthorized.

Step 5: Protecting Pages in Next.js

There are two levels of protection.

Client-side protection:

Server-side protection (more secure):

Using middleware in Next.js.

Example scenario:

If user tries to access /dashboard without authentication, middleware checks cookie and redirects to /login.

This prevents even initial rendering of protected pages.

Step 6: Using Next.js Middleware

Create a middleware.js file in your Next.js project.

Middleware logic:

This works especially well in Next.js App Router architecture.

Optional: Using NextAuth.js

If you want to avoid building everything manually, you can use NextAuth.

NextAuth supports:

It reduces boilerplate and improves security.

However, for enterprise systems using custom backend APIs, manual JWT handling is often preferred for full control.

Real-World Example Scenario

Let’s say you are building a SaaS billing dashboard.

Without authentication:

Anyone can access financial reports.

With proper authentication:

Authentication is not just login. It is identity verification + access control.

Common Mistakes Developers Make

Always configure CORS properly:

Advantages of JWT-Based Authentication

Disadvantages

Summary

Implementing authentication in Next.js with a backend API involves creating a secure login endpoint, generating JWT tokens, storing them safely using HTTP-only cookies, and protecting both API routes and frontend pages using middleware. When implemented correctly, this approach ensures scalable, stateless, and secure authentication suitable for SaaS platforms, enterprise dashboards, and production-grade web applications. The key to success lies in proper token handling, secure cookie configuration, strict backend validation, and thoughtful route protection to prevent unauthorized access.