kapsys-logo
Expertise
Technologies
Blog
Contact Us
Blog

How to Implement Authentication in Next.js Apps

February 11, 2024 by Sara Wahba
  • User Experience
nextjs authentication

Authentication is a pivotal aspect of modern web applications, ensuring only authorized users can access specific resources or functionalities. Next.js, a popular React framework, offers developers the tools and flexibility to implement robust authentication mechanisms. This article from Kapsys explores the fundamentals of Next.js authentication, covering everything from setting up basic authentication to securing routes and API endpoints. 

Understanding Next.js Authentication

Next.js does not come with built-in authentication features. Instead, it provides versatile API and server-side rendering capabilities that allow developers to integrate various authentication strategies, such as JWT (JSON Web Tokens), OAuth, and third-party authentication services like Auth0 or Firebase.

Implementing Basic Authentication in Next.js

  • Setting Up Your Next.js Project

If you haven't done so, create a new Next.js project. You can do this by running the following command: 

npx create-next-app@latest your-project-name
  • Choosing an Authentication Strategy

Decide on the authentication strategy that best fits your application's requirements. For simplicity, this guide will focus on JWT-based authentication, a common choice for its statelessness and scalability.

next js authentication

Implementing JWT Authentication

Implementing JWT (JSON Web Token) authentication in a web application involves several key steps: generating tokens upon user login, verifying these tokens in subsequent requests to protect routes, and optionally, handling token refresh mechanisms for maintaining session continuity. Here, we'll focus on a simple JWT authentication flow, commonly used in applications built with frameworks like Express.js for Node.js, or integrating JWT into frontend applications.

  • Installing Dependencies

First, you'll need to install a few packages to help with authentication:

npm install jsonwebtoken bcryptjs
  • jsonwebtoken for creating and verifying JWT tokens.
  • bcryptjs for hashing and comparing passwords securely.
  • Creating the Authentication API Routes

Next.js allows you to create API routes that can handle authentication logic. Create a new file under pages/api/auth/login.js and add the following code to handle user login:

import jwt from 'jsonwebtoken';
import bcrypt from 'bcryptjs';
// Dummy user data - replace this with your database logic
const users = [{ id: 1, username: 'user', password: '$2a$10$...' }];

export default function handler(req, res) {
  const { username, password } = req.body;
  const user = users.find(u => u.username === username);
  if (!user) {
    return res.status(400).json({ error: 'User not found' });
  }
  if (!bcrypt.compareSync(password, user.password)) {
    return res.status(401).json({ error: 'Invalid password' });
  }
  const token = jwt.sign({ id: user.id }, 'your-secret-key', { expiresIn: '1h' });
  res.status(200).json({ token });
}

Protecting Routes in Next.js

With your authentication API in place, the next step is to protect specific routes or pages in your application.

Creating a Higher-Order Component for Protected Routes

A higher-order component (HOC) can wrap around your Next.js pages to protect them. This component checks if the user is authenticated (e.g., by verifying a JWT token) before rendering the page.

Create a file named withAuth.js in a utils or components directory with the following content:

import { useEffect } from 'react';
import { useRouter } from 'next/router';
import jwt from 'jsonwebtoken';

const withAuth = Component => props => {
  const router = useRouter();
  useEffect(() => {
    const token = localStorage.getItem('token');
    if (!token) {
      router.push('/login');
    } else {
      try {
        jwt.verify(token, 'your-secret-key');
      } catch (error) {
        router.push('/login');
      }
    }
  }, []);

  return <Component {...props} />;
};

export default withAuth;

To protect a page, simply wrap the export of your page component with this HOC:

import withAuth from '../utils/withAuth';

function ProtectedPage() {
  return <div>Protected content</div>;
}

export default withAuth(ProtectedPage);

Next.js API Authorization

For securing your API routes, you can implement a simple middleware that verifies the JWT token in the request headers.

Create a file named authMiddleware.js under a middlewares directory with the following content:

import jwt from 'jsonwebtoken';

const authMiddleware = (req, res, next) => {
  try {
    const token = req.headers.authorization.split(' ')[1];
    jwt.verify(token, 'your-secret-key');
    next();
  } catch (error) {
    res.status(401).send('Unauthorized');
  }
};

export default authMiddleware;

You can then use this middleware in your API routes to ensure that only authenticated requests can access them:

import authMiddleware from '../../middlewares/authMiddleware';

export default function handler(req, res) {
  authMiddleware(req, res, () => {
    // Your API logic here
  });
}

Conclusion

Implementing authentication in Next.js applications requires a solid understanding of the Next.js framework and the underlying principles of web authentication. Following the steps outlined in this guide, developers can effectively secure their Next.js applications, protect sensitive routes, and ensure authorized users access only APIs. As you build more complex applications, consider further exploring advanced authentication features and third-party services to enhance your app's security and user experience.