Next.js  

How to Implement Authentication Using Next.js and a Backend API?

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:

  • Frontend: Next.js application

  • Backend: REST API (Node.js, .NET, etc.)

  • Database: Stores users and hashed passwords

  • Authentication Method: JWT-based authentication

Here’s how the login flow works:

  • User enters email and password.

  • Next.js sends credentials to the backend API.

  • Backend validates credentials.

  • Backend generates a JWT access token.

  • Token is returned to Next.js.

  • Token is stored securely.

  • Future requests include the token in the Authorization header.

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:

POST /api/auth/login

Backend logic should:

  • Validate email and password

  • Compare password with hashed value

  • Generate JWT token

  • Return token to frontend

A typical response looks like this:

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

Important security practices:

  • Always hash passwords (bcrypt or similar)

  • Use HTTPS in production

  • Set short expiry for access tokens

  • Optionally use refresh tokens

Step 2: Creating Login in Next.js

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

Inside your login function:

  • Collect email and password.

  • Send POST request to backend API.

  • Receive access token.

  • Store the token securely.

Example logic (simplified explanation):

  • Call fetch ("https://yourapi.com/api/auth/login")

  • Send credentials in body

  • Store returned token

Where Should You Store the Token?

This is extremely important.

There are three common approaches:

  • localStorage

  • sessionStorage

  • HTTP-only cookies

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:

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:

GET /api/user/profile

The browser automatically sends the cookie.

Backend middleware should:

  • Read token from cookie

  • Verify JWT signature

  • Attach user data to request

  • Allow or deny access

If token is invalid, return 401 Unauthorized.

Step 5: Protecting Pages in Next.js

There are two levels of protection.

Client-side protection:

  • Check authentication state.

  • Redirect to login if user is not authenticated.

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:

  • Read cookies

  • Validate token

  • Redirect if invalid

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:

  • JWT authentication

  • OAuth providers (Google, GitHub)

  • Credentials provider (custom backend)

  • Session management

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:

  • Users log in.

  • Token verifies identity.

  • Backend validates subscription.

  • Only authorized users see billing data.

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

Common Mistakes Developers Make

  • Storing tokens in localStorage in production.

  • Not setting Secure flag on cookies.

  • Not handling token expiry.

  • Not validating JWT on every request.

  • Forgetting CORS configuration when frontend and backend are on different domains.

Always configure CORS properly:

  • Allow credentials

  • Set correct origin

  • Enable cookie transmission

Advantages of JWT-Based Authentication

  • Stateless authentication

  • Scalable across microservices

  • Works well with REST APIs

  • No server session storage needed

Disadvantages

  • Token revocation is complex

  • If token is stolen, it works until expiry

  • Requires careful security configuration

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.