Cookies in Next.js

Join our Newsletter

Subscribe to our newsletters

and stay updated

While you subscribe you agree to our Privacy Policy and Terms of Service apply.

Not using ?

16 May 2024

All About Cookies in Next.js

Ed Robinson, Lead Software Engineer

Introduction to Cookies in Next.js

Cookies have been an essential part of web development for decades, allowing developers to store and retrieve small pieces of data on the client-side. In the context of Next.js, a popular React framework for building server-rendered applications, cookies play a crucial role in managing user sessions, authentication, and personalization. This section will provide an overview of cookies and their importance in Next.js applications.

Learn more about the advantages of using Next.js.

What are Cookies and Why are They Important?

Cookies are small text files that are stored on a user's device by a website. They contain key-value pairs of data that can be read and written by the server and the client. Cookies are commonly used for the following purposes:

  • Session Management: Cookies can store session tokens or user preferences, allowing the server to identify and maintain the state of a user's session across multiple requests.

  • Authentication: Cookies are often used to store authentication tokens, enabling users to remain logged in even after closing the browser or navigating away from the website.

  • Personalization: Cookies can store user preferences, such as language settings or customized layouts, to provide a personalized experience for returning visitors.

In Next.js applications, cookies are particularly important for server-side rendering and API route handling. They allow developers to access and modify cookie data on both the client-side and server-side, enabling seamless integration with authentication systems and personalized user experiences.

Client-Side vs. Server-Side Cookie Handling

Next.js provides different approaches for handling cookies depending on whether you are working on the client-side or server-side of your application.

  • Client-Side Cookie Handling:

    • On the client-side, you can use the document.cookie API to read and write cookies using JavaScript.

    • This approach is suitable for client-side rendered pages and components that need to access or modify cookies in response to user interactions.

    • However, client-side cookie handling has limitations, such as the inability to set HttpOnly cookies, which are inaccessible to JavaScript for enhanced security.

  • Server-Side Cookie Handling:

    • Next.js provides built-in support for handling cookies on the server-side through the req.cookies object in API routes and the getServerSideProps function in pages.

    • Server-side cookie handling allows you to read and write cookies securely, including setting HttpOnly cookies that cannot be accessed by client-side JavaScript.

    • This approach is particularly useful for authentication, session management, and protecting sensitive data.

By leveraging both client-side and server-side cookie handling techniques, developers can build robust and secure Next.js applications that effectively manage user sessions and authentication.

Built-in Cookie Support in Next.js

Next.js offers built-in support for handling cookies through various APIs and libraries. Some of the key features and approaches include:

  1. API Routes:

    • Next.js allows you to create API routes that handle HTTP requests and responses, including cookie manipulation.

    • In API routes, you can access cookies using req.cookies and set cookies using res.setHeader('Set-Cookie', ...).

  2. getServerSideProps:

    • The getServerSideProps function in Next.js pages enables server-side rendering and provides access to the incoming request and response objects.

    • You can read cookies using req.cookies and set cookies using res.setHeader('Set-Cookie', ...) within this function.

  3. next/headers:

    • Next.js 13 introduced the next/headers module, which provides a cookies() function for reading and writing cookies in Server Components, Server Actions, and Route Handlers.

    • The cookies() function offers methods like get(), set(), and delete() to manage cookies with options like secure, httpOnly, path, and expires.

  4. Third-Party Libraries:

    • Next.js developers can also leverage third-party libraries like cookies-next or js-cookie to simplify cookie handling and provide a more convenient API.

    • These libraries offer cross-browser compatibility and additional features for managing cookies in Next.js applications.

By utilizing these built-in features and libraries, developers can efficiently handle cookies in their Next.js applications, ensuring secure and seamless user experiences.

When building Next.js applications, it's worth considering the benefits of using a headless CMS like Caisy. A headless CMS decouples the content management from the presentation layer, allowing developers to focus on building the frontend while content editors work independently on managing the content. This separation of concerns enables greater flexibility and scalability in Next.js projects. With Caisy's API-driven approach and seamless integration with Next.js, developers can easily fetch and display content, including personalized experiences based on user preferences stored in cookies. By combining the power of Next.js's cookie handling capabilities with a headless CMS like Caisy, developers can create dynamic and content-rich applications with ease. Learn what else makes caisy the perfect Headless CMS for developers.

Headless CMS for developers

Your terms, your stack. Experience unmatched speed and flexibility with caisy - the headless CMS you've been dreaming of.

A graphic showing caisy's benefits for developers, including frameworks and features.

Setting and Retrieving Cookies in Next.js

When working with cookies in Next.js applications, you have several options depending on whether you need to handle cookies on the client-side or server-side. Let's explore the different approaches and techniques for setting and retrieving cookies in Next.js.

Client-Side Cookie Management with document.cookie

For client-side cookie management, you can use the document.cookie property to set and retrieve cookies. Here's an example of how to set a cookie on the client-side:

document.cookie = "username=John Doe; expires=Thu, 18 Dec 2025 12:00:00 UTC; path=/";

To retrieve a cookie value on the client-side, you can use the following code:

const cookieValue = document.cookie
  .split('; ')
  .find((row) => row.startsWith('username='))
  ?.split('=')[1];

Server-Side Cookie Management with req.cookies and res.setHeader

When handling cookies on the server-side in Next.js, you can access incoming cookies using req.cookies and set outgoing cookies using res.setHeader('Set-Cookie', ...). Here's an example of setting a cookie in a Next.js API route:

export default function handler(req, res) {
  res.setHeader('Set-Cookie', 'username=John Doe; HttpOnly; Max-Age=3600; Path=/');
  res.status(200).json({ message: 'Cookie set successfully' });
}

To retrieve a cookie value on the server-side, you can use req.cookies:

export default function handler(req, res) {
  const username = req.cookies.username;
  res.status(200).json({ username });
}

Using the cookies() Function in Next.js 13

Starting from Next.js 13, the cookies() function provides a convenient way to read and set cookies in Server Components and Server Actions. However, it's important to note that Server Components cannot directly set cookies. Instead, you need to use API calls, client-side JavaScript, or middleware to modify cookies.

Here's an example of using the cookies() function to read a cookie value in a Server Component:

import { cookies } from 'next/headers';

export default function MyComponent() {
  const cookieStore = cookies();
  const username = cookieStore.get('username')?.value;

  return <div>Welcome, {username}!</div>;
}

Simplifying Cookie Handling with the cookies-next Package

To simplify cookie handling in Next.js, you can use the cookies-next package. It provides a set of functions for setting, getting, checking, and deleting cookies, and it works seamlessly on both the client-side and server-side.

Here's an example of using cookies-next to set a cookie on the client-side:

import { setCookie } from 'cookies-next';

setCookie('username', 'John Doe', { maxAge: 60 * 60 * 24, path: '/' });

To retrieve a cookie value using cookies-next, you can use the getCookie function:

import { getCookie } from 'cookies-next';

const username = getCookie('username');

The cookies-next package simplifies cookie handling and provides a consistent API for both client-side and server-side cookie management in Next.js applications.

Secure Cookie Handling Best Practices

When working with cookies in Next.js, it's crucial to follow secure cookie handling practices to protect your application and users from potential vulnerabilities. In this section, we'll explore several best practices for ensuring the security of cookies in your Next.js application.

Securing Cookies with HttpOnly, Secure, and SameSite Flags

To enhance the security of your cookies, you should set the following flags:

  • HttpOnly: This flag prevents client-side JavaScript from accessing the cookie, mitigating the risk of cross-site scripting (XSS) attacks.

  • Secure: When set, the cookie will only be transmitted over a secure HTTPS connection, protecting it from being intercepted by malicious actors.

  • SameSite: This flag controls the cross-site behavior of cookies. Setting it to Strict or Lax helps protect against cross-site request forgery (CSRF) attacks.

Here's an example of setting these flags when creating a cookie in Next.js:

res.setHeader('Set-Cookie', `myCookie=value; HttpOnly; Secure; SameSite=Strict`);

Encrypting and Signing Cookies to Prevent Tampering

To prevent unauthorized modification of cookies, consider encrypting and signing them. Encryption ensures that the cookie's content remains confidential, while signing allows you to detect any tampering attempts.

You can use libraries like iron-session or jose to handle cookie encryption and signing in Next.js. These libraries provide easy-to-use APIs for securing your cookies.

Avoiding Sensitive Data Storage in Cookies

Avoid storing sensitive information, such as authentication tokens or personal data, directly in cookies. Cookies are vulnerable to client-side access and can be compromised if not properly secured.

Instead, consider using server-side session storage or token-based authentication mechanisms. Store only a session identifier or a reference to the sensitive data in the cookie, while keeping the actual data securely stored on the server.

Handling Cross-Origin Cookie Restrictions

When making cross-origin requests, be cautious about how cookies are handled. By default, cookies are not sent with cross-origin requests unless explicitly allowed.

To enable cross-origin cookie sharing, you need to set the withCredentials option to true when making the request. Additionally, the server must include the Access-Control-Allow-Credentials header set to true and specify the allowed origins in the Access-Control-Allow-Origin header.

Here's an example of making a cross-origin request with cookies enabled:

fetch('https://api.example.com/data', {
  credentials: 'include',
});

Remember to carefully consider the security implications before enabling cross-origin cookie sharing and ensure that proper access controls and authentication mechanisms are in place.

Authentication and Session Management with Cookies

When it comes to implementing authentication and session management in Next.js applications, cookies play a crucial role. In this section, we'll explore how to leverage cookies to handle user authentication flows, manage sessions securely, and protect API routes.

Implementing Authentication Flows using Server Actions

To implement authentication flows in Next.js, you can utilize Server Actions. When a user submits their credentials through a form, the form sends a request to an API route. The API route then verifies the credentials and indicates whether the authentication was successful or not. If the verification fails, an error message is displayed to the user.

Here's a simplified example of an authentication flow using Server Actions:

// pages/api/login.js
export default function handler(req, res) {
  if (req.method === 'POST') {
    const { username, password } = req.body;
    // Verify the credentials
    if (username === 'admin' && password === 'password') {
      // Set a cookie to indicate successful authentication
      res.setHeader('Set-Cookie', 'authenticated=true; HttpOnly; Secure');
      res.status(200).json({ message: 'Login successful' });
    } else {
      res.status(401).json({ message: 'Invalid credentials' });
    }
  } else {
    res.status(405).json({ message: 'Method not allowed' });
  }
}

Stateless Sessions with Signed Cookies

One approach to session management in Next.js is using stateless sessions with signed cookies. In this approach, the session data is stored in the browser's cookies and sent with each request for server-side verification. The server signs the cookie to ensure its integrity and prevent tampering.

To implement stateless sessions with signed cookies, you can use libraries like iron-session or jose. These libraries provide convenient APIs for signing and verifying cookies securely.

Example using iron-session:

// pages/api/profile.js
import { withIronSessionApiRoute } from 'iron-session/next';

export default withIronSessionApiRoute(
  function handler(req, res) {
    // Access the user session data from the signed cookie
    const { user } = req.session;
    if (user) {
      res.status(200).json({ name: user.name, email: user.email });
    } else {
      res.status(401).json({ message: 'Unauthorized' });
    }
  },
  {
    cookieName: 'myapp_cookiename',
    password: 'complex_password_at_least_32_characters_long',
    cookieOptions: {
      secure: process.env.NODE_ENV === 'production',
    },
  }
);

Database-Backed Sessions for Secure Authorization

For more secure authorization, you can opt for database-backed sessions. In this approach, the session data is stored in a database, and the browser only receives an encrypted session ID. This allows for more granular control over session expiration and revocation.

To implement database-backed sessions, you can use libraries like next-auth or next-iron-session. These libraries provide built-in support for storing session data in databases like MongoDB, PostgreSQL, or Redis.

Example using next-auth:

// pages/api/auth/[...nextauth].js
import NextAuth from 'next-auth';
import Providers from 'next-auth/providers';

export default NextAuth({
  providers: [
    Providers.Credentials({
      async authorize(credentials) {
        // Verify the credentials and return the user object
        // ...
      },
    }),
  ],
  database: process.env.DATABASE_URL,
  session: {
    jwt: true,
  },
  callbacks: {
    async jwt(token, user) {
      if (user) {
        token.user = user;
      }
      return token;
    },
    async session(session, token) {
      session.user = token.user;
      return session;
    },
  },
});

Protecting API Routes and Verifying User Authentication

To ensure that only authenticated users can access specific API routes, you need to protect those routes and verify the user's authentication status. You can achieve this by checking the presence and validity of the authentication cookie or session token in the API route handlers.

Here's an example of protecting an API route:

// pages/api/protected.js
import { withIronSessionApiRoute } from 'iron-session/next';

export default withIronSessionApiRoute(
  function handler(req, res) {
    const { user } = req.session;
    if (!user) {
      res.status(401).json({ message: 'Unauthorized' });
      return;
    }
    // User is authenticated, handle the request
    // ...
  },
  {
    cookieName: 'myapp_cookiename',
    password: 'complex_password_at_least_32_characters_long',
    cookieOptions: {
      secure: process.env.NODE_ENV === 'production',
    },
  }
);

By implementing these authentication and session management techniques using cookies in Next.js, you can ensure secure user authentication, protect sensitive routes, and maintain user sessions effectively.

Advanced Cookie Techniques and Considerations

When working with cookies in Next.js, there are several advanced techniques and considerations to keep in mind to ensure secure and efficient cookie handling. In this section, we'll explore using middleware for optimistic authorization checks, logging and monitoring cookie-related activity, handling cookie-related errors and edge cases, and regularly reviewing cookie usage and security practices.

Using Middleware for Optimistic Authorization Checks

Middleware in Next.js allows you to intercept and modify incoming requests before they reach your application's routes. You can leverage middleware to perform optimistic authorization checks based on the user's session data stored in cookies. Here's an example of how you can use middleware for authorization:

import { NextResponse } from 'next/server';
import { verifyToken } from './lib/auth';

export async function middleware(request) {
  const token = request.cookies.get('sessionToken')?.value;

  if (token) {
    const decodedToken = await verifyToken(token);
    if (decodedToken) {
      return NextResponse.next();
    }
  }

  return NextResponse.redirect(new URL('/login', request.url));
}

In this example, the middleware checks for the presence of a sessionToken cookie. If the token exists, it is verified using a verifyToken function. If the token is valid, the request is allowed to proceed to the next middleware or route handler. If the token is missing or invalid, the user is redirected to the login page.

It's important to note that middleware should be used for optimistic checks and avoid performing database queries or expensive operations to prevent performance issues.

Logging and Monitoring Cookie-Related Activity

Logging and monitoring cookie-related activity can help you detect and investigate suspicious behavior or potential security breaches. You can implement logging mechanisms to track events such as:

  • Cookie creation and modification

  • Failed authentication attempts

  • Unauthorized access attempts

  • Unusual cookie values or patterns

By logging these events, you can gain insights into potential security risks and take appropriate actions. Consider using a logging framework or service that allows you to centralize and analyze log data efficiently.

Handling Cookie-Related Errors and Edge Cases

When working with cookies, it's crucial to handle errors and edge cases gracefully to prevent vulnerabilities and ensure a smooth user experience. Some common scenarios to consider include:

  • Missing or invalid cookies

  • Expired or tampered cookies

  • Cookies exceeding size limits

  • Cookies blocked by browser settings or extensions

Implement appropriate error handling and fallback mechanisms to handle these scenarios. For example, if a required cookie is missing, you can redirect the user to a login page or display an error message. If a cookie exceeds the size limit, you may need to split the data across multiple cookies or consider alternative storage mechanisms.

Regular Review of Cookie Usage and Security Practices

Security threats and best practices evolve over time, so it's essential to regularly review your cookie usage and security practices. Conduct periodic audits to:

  • Assess the necessity and purpose of each cookie

  • Validate the security measures in place (e.g., secure flags, encryption)

  • Update dependencies and libraries to address any known vulnerabilities

  • Review access controls and authorization mechanisms

  • Evaluate the effectiveness of logging and monitoring practices

By staying proactive and regularly reviewing your cookie implementation, you can identify and address potential vulnerabilities before they can be exploited.

Recommended Libraries and Resources

As you embark on your journey of mastering cookies in Next.js, it's essential to have a solid toolkit and a wealth of knowledge at your disposal. In this section, we'll explore some recommended libraries and resources that can streamline your development process and enhance your understanding of cookie handling and security in Next.js.

Authentication Libraries for Next.js

When it comes to implementing authentication in your Next.js application, several libraries can simplify the process and provide robust features out of the box. Some popular authentication libraries for Next.js include:

  • NextAuth.js: A complete authentication solution for Next.js, supporting various authentication providers and offering built-in session management.

  • Auth0: A powerful authentication platform that integrates seamlessly with Next.js, providing features like social login, multi-factor authentication, and user management.

  • Supabase: An open-source Firebase alternative that offers authentication services alongside a real-time database and storage capabilities.

These libraries abstract away many of the complexities involved in implementing authentication, allowing you to focus on building your application's core functionality.

Session Management Libraries

Efficient session management is crucial for maintaining user state and securing your application. Here are a couple of libraries that can help you handle sessions in Next.js:

  • Iron Session: A lightweight session management library for Next.js that uses signed and encrypted cookies to store session data securely.

  • Jose: A library for working with JSON Web Tokens (JWTs) in Next.js, enabling stateless session management and secure communication between the client and server.

By leveraging these libraries, you can implement secure and scalable session management without reinventing the wheel.

Understanding Common Web Vulnerabilities (XSS and CSRF)

As a developer, it's crucial to be aware of common web vulnerabilities and how to mitigate them. Two prevalent vulnerabilities are Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF). Here are some resources to help you understand and prevent these vulnerabilities:

  • "Understanding XSS Attacks" by OWASP: A detailed explanation of XSS attacks, including different types and prevention techniques.

  • "Understanding CSRF Attacks" by OWASP: An in-depth look at CSRF attacks, including how they work and best practices for prevention.

By familiarizing yourself with these vulnerabilities and implementing appropriate countermeasures, you can enhance the security of your Next.js application.

In conclusion, mastering cookies in Next.js is a critical skill for developers building modern web applications. By understanding the concepts, best practices, and leveraging the recommended libraries and resources, you can effectively handle cookies, implement secure authentication and session management, and protect your application from common vulnerabilities.

As you embark on your Next.js development journey, consider exploring caisy, a high-performing headless CMS. With its remarkable speed, user-friendly interface, and powerful features like blueprint functionality and a GraphQL API, caisy empowers developers to create and manage content effortlessly. Its scalable multi-tenancy system and comprehensive Digital Asset Management system streamline project management, making it an ideal choice for developers seeking efficiency and flexibility.

With its flexible pricing tiers and partnership opportunities, caisy caters to projects of varying budgets and scopes, ensuring that you have the tools you need to succeed.

So why not give caisy a try? Sign up for a free account today and experience the power and flexibility of this innovative headless CMS. With caisy by your side, you'll be well-equipped with one of the best Headless CMS for Next.js applications while efficiently managing your content and assets.

Focus on Your Code
Let caisy Handle the Content.

single caisy logo without name
Capterra Reviews

Subscribe to our newsletters

and stay updated

While you subscribe you agree to our Privacy Policy and Terms of Service apply.