Authentication

Next.js Authentication: Code Examples and Libraries to Get You Started

Next.js is a full-stack framework that offers multiple authentication patterns for different use cases. The Next.js framework allows developers to build single-page JavaScript applications. It focuses on performance and out-of-the-box support for Server-Side Rendering (SSR).

It provides a minimal setup for developers to get started and features a fast development cycle with automatic code splitting, optimized builds, and easy client-side and server-side rendering.

What Is Next.js Authentication? 

Next.js Aauthentication helps ensure that only authorized users can access a Next.js website or application and its data. It helps to protect sensitive information and prevents unauthorized access. This is commonly achieved through methods such as login and password authentication, OAuth, or JWT tokens. Next.js has three authentication patterns (in this article we focus on the first two):

  • Static page authentication
  • Dynamic page authentication
  • API route

Authentication verifies a user’s identity, while authorization controls what a user can access. Next.js handles the entire authentication and authorization process, including user sign-up, sign-in, and sign-out. 

There are three libraries commonly used for Next.js authentication:

  • NextAuth.js: A secure and scalable open-source authentication library that handles the entire authentication process, including sign-up, sign-in, and sign-out. It is designed to sync with any OAuth service, can be used with or without a database, and has default support for popular databases such as MySQL, MongoDB, PostgreSQL, and MariaDB. NextAuth.js has built-in support for popular services such as Google, Facebook, Auth0, and Apple. It also supports email, passwordless, and magic link.
  • Passport.js: A flexible and modular authentication middleware for Node.js, designed to authenticate requests. Instead of prescribing how authentication must be conducted, Passport provides a series of strategies to perform authentication.
  • Iron Session: A Node.js utility that employs signed and encrypted cookies for data storage, compatible with Next.js, Express, and Node.js HTTP servers. The session information is kept in encrypted cookies, which only the server can decrypt.

Once a user has a session in Next.js, they can access pages or call API endpoints that require authentication. The client application sends the session cookie along with each request, which makes the user information available on the server-side automatically.

In this article:

Next.js Rendering Patterns 

There are three ways that Next.js can render pages. These rendering patterns are:

  • Client-Side Rendering (CSR): The browser executes JavaScript to render the content dynamically on the client side. This means that the user’s browser will download and run JavaScript code that will generate the content for the user to view. This can lead to a faster initial loading experience, as the amount of data sent from the server to the client is minimized. However, the overall performance can be impacted if the JavaScript code is complex or if the user has a slow internet connection, as the rendering will be slower.
  • Server-Side Rendering (SSR): The server generates and sends an HTML page to the client, which is then displayed directly in the browser. This approach can lead to slower initial loading times, as the server has to generate the entire HTML page and send it to the client. However, the user can see the content immediately, even if they have a slow internet connection, as the page has already been pre-rendered by the server.
  • Static Site Generation (SSG): The HTML pages are pre-rendered at build time, which results in faster loading times and improved SEO, as the content is already available to search engines. This approach is best for sites that don’t have frequently changing content or that don’t require user interaction, such as blogs or portfolios.

The Next.js Authentication Process

Next.js offers a variety of options to handle this essential security function.

  1. Request initiation: when a user tries to access a secured page or feature, the application initiates an authentication request. This might involve redirecting the user to a login page if they aren’t already authenticated.
  2. Data submission: the user provides their credentials, typically a username and password, or opts for a third-party authentication method (like Google or Facebook).
  3. Verification: Next.js interacts with its backend or third-party services (like NextAuth.js or Passport.js) to verify the provided credentials. If using a database, it will check the input against stored user data.
  4. Session creation: once authenticated, a session is initiated. As mentioned previously, the client application sends the session cookie with each request, ensuring seamless navigation through protected areas without the need for re-authentication.
  5. Access or denial: depending on whether the credentials are valid, Next.js either grants access or denies it. If access is granted, the user can seamlessly interact with the secured areas of the application. If denied, an error message or redirect might be initiated.
  6. Middleware integration: for finer control, middleware can be integrated into the Next.js authentication process. For instance, Passport.js can act as a middleware, assisting in the authentication flow.

Ending the session: typically, the session will time out after a certain period of inactivity or can be ended manually by the user through a logout action.

Next.js Authentication Patterns 

Static Page Authentication

This type of authentication applies to statically generated pages. They don’t have any data requirements that would block the page from rendering, such as getServerSideProps or getInitialProps. A static page renders the loading state and fetches the user from the client-side.

This pattern allows Next.js to serve preloaded pages from the central CDN – i.e., implementing authentication on pages that are pre-rendered at build time. This results in faster interactions.

Here is an example script for a profile page in Next.js using static page authentication:
Note: The next-auth/client package has been deprecated. In this example, we’ll use the next-auth/react package.

Install it by running this command:

npm install next-auth

Modify the _app.tsx file located in <next_js_project_folder>/pages/_app.tsx to include the SessionProvider library from the next-auth/react package:

import type { AppProps } from 'next/app'
import { SessionProvider } from "next-auth/react"

export default function App({
Component, pageProps: { session, ...pageProps }, }) {

  return (
        <SessionProvider session={session}>
        <Component {...pageProps} />
        </SessionProvider>
  )
}

Add following code to <next_js_project_folder>/pages/index.tsx:

import { useSession  } from 'next-auth/react'

//const inter = Inter({ subsets: ['latin'] })


export default function Home() {
  const { data: session } = useSession()

if (session) {
         return <p>Authenticated</p>

}

return <p>Not Authenticated</p>
}

When you try to access the application via a web browser, the output should look like this:

Dynamic Page Authentication

This pattern applies to pages that are generated dynamically based on the URL. In other words, it’s the process of securing pages that are not statically defined in the code, but rather generated dynamically based on the URL. This prevents the exposure of unauthorized content before Next.js redirects the page.

Here’s an example of dynamic authentication for a profile page in Next.js using the getServerSideProps method:

import { useRouter } from 'next/router';
import axios from 'axios';

const ProfilePage = ({ user }) => {
  const router = useRouter();
  const { userId } = router.query;

  if (!user) {
    return <div>Not authorized</div>;
  }

  return (
    <div>
      <h1>Welcome, {user.name}</h1>
      <p>Your email is {user.email}</p>
    </div>
  );
};

export async function getServerSideProps({ req, res, query }) {
  const { userId } = query;

  try {
    const { data } = await axios.get(`
https://reqres.in/api/users/$(userId)`);

    if (!data.data.id) {
      res.statusCode = 404;
      return { props: { user: null } };
    }
   
    const { data: currentUser } = await axios.get('https://reqres.in/api/users/2', {
          });

    if (!== data.data.id) {
      res.statusCode = 403;
      return { props: { user: null } };
    }

    return { props: { user: data.data} };
  } catch (error) {
    console.error(error);
    res.statusCode = 500;
    return { props: { user: null } };
  }
}

export default ProfilePage;

The output should look like this:

Note: The above code uses a free testing API, reqres.in. The API has the following data structure:

{
    "data": {
        "id": 2,
        "email": "janet.weaver@reqres.in",
        "first_name": "Janet",
        "last_name": "Weaver",
        "avatar": "https://reqres.in/img/faces/2-image.jpg"
    },
    "support": {
        "url": "https://reqres.in/#support-heading",
        "text": "To keep ReqRes free, contributions towards server costs are appreciated!"
    }
}

API Route

API route authentication is the method of securing API endpoints in Next.js applications. By using this pattern, developers ensure that only authenticated users or applications can make requests to specific API routes. Here’s how this can be achieved:

  • Define an API Route: In Next.js, API routes reside within the pages/api directory. For example, you might have an endpoint called /api/user.
  • Implement Middleware: Implement middleware functions like authentication checks within your API route. This middleware can verify JSON Web Tokens (JWT), check session cookies, or any other method you’ve chosen for authentication.

Handle Requests: Based on the result of your middleware (authenticated or not), your API route can respond appropriately. For instance, if a user is not authenticated, you can return a 401 Unauthorized status. If they are authenticated, you can proceed with the request, fetch data, or perform any other necessary tasks.

Open Source Next.js Authentication Libraries 

NextAuth.js

NextAuth.js, which will be replaced by Auth.js in the near future, is an authentication and authorization library for Next.js. NextAuth.js provides a simple and flexible way to implement authentication and authorization functionality within Next.js applications. It operates with or without a database and natively supports widely-used databases like MySQL, MongoDB, PostgreSQL, and MariaDB.

NextAuth.js integrates with various identity providers, such as Google, Facebook, and Twitter, to allow users to log in using their existing accounts. It also supports email/password authentication, session management, and token-based authentication.

NextAuth.js handles the entire authentication and authorization process, including user sign-up, sign-in, and sign-out. It provides a secure and scalable solution for managing user authentication and authorization in Next.js applications.

Passport.js

Passport.js is a popular authentication middleware for Node.js that provides a simple and flexible way to add authentication to web applications. Passport.js supports a wide range of authentication strategies, including local authentication (using email/password), OAuth-based authentication (using social media platforms like Facebook, Twitter, and Google), and token-based authentication (using JSON Web Tokens, JWT).

Passport.js can be used in Next.js applications to implement authentication and authorization. To do this, Passport.js is integrated into the Next.js server-side runtime, where it can handle authentication requests and manage user sessions.

To use Passport.js in a Next.js application, you would typically create a middleware function that initializes Passport.js and sets up the desired authentication strategies. This middleware function would be included in the Next.js server-side runtime, so that it can be executed for every incoming request.

Iron Session 

Iron Session is a session middleware for the Iron framework, which is a high-level web framework for the Rust programming language. It allows you to store session data on the server, which can be used to persist information across multiple requests from the same client.

In a web application, a session is a mechanism for storing data on the server that is associated with a specific client. This data can be used to track the client’s activity and maintain state between requests. The Iron Session middleware provides a simple and secure way to manage sessions in a Rust web application.

With Iron Session, you can store data such as the user’s session ID, login status, and other information, and retrieve this data on subsequent requests to the server. This allows you to build web applications that can maintain state and provide a seamless experience for the user.

Authentication and Authorization with Frontegg

The industry standard today is to use Authentication providers to “build the door”, but what about Authorization (the door knob)? Most authentication vendors don’t go that extra mile, forcing SaaS vendors to invest in expensive in-house development or look for third-party fixes that introduce more technical challenges. This often delays investment in core technology development, which negatively impacts innovation and time-to-market (TTM) metrics. 

Frontegg’s end-to-end user management platform allows you to authenticate and authorize users with just a few clicks. Integration takes just a few minutes and lines of code, thanks to its plug-and-play nature. It’s also multi-tenant by design. 

START FOR FREE