Part 120: Enhancing Authentication with Cookies in Next.js

[App] Authentication Overview

[App] Authentication Overview

In our journey to implement a robust sign-in functionality, we've reached a critical point. Although we've successfully redirected users to the home page upon entering valid credentials, we aren't truly logging them in. The NavBar still displays the "Sign in" link, indicating that our app doesn’t recognize the user as authenticated. To address this, we need a mechanism to persist user login information across page reloads. Let's dive into how we can achieve this using cookies in a Next.js application.

Why Use Cookies for Authentication?

When considering where to store user data, we have several options:

  • Local Storage and IndexedDB: These client-side storage solutions are versatile but require JavaScript and do not automatically persist data across sessions.

  • Cookies: These are automatically managed by the browser and can be set by the server without client-side JavaScript, making them ideal for authentication. They can also be more secure when configured correctly.

Given these advantages, we'll use cookies for our authentication flow.

Step 1: Importing the Necessary Functions

Next.js provides a convenient cookies function from the next/headers module. This function returns a ReadonlyRequestCookies object, which, despite its name, allows us to set cookies in the server's response.

Step 2: Modifying the signInAction

In our server action file, we'll set a cookie named "user" upon successful login. This cookie will store the user's email in a JSON format.

// File path: app/sign-in/actions.js

'use server';


import { redirect } from 'next/navigation';

export async function signInAction(formData) {
  const email = formData.get('email');
  const password = formData.get('password');
  const user = authenticate(email, password);
  
  if (!user) {
    return { isError: true, message: 'Invalid credentials' };
  }

  
  redirect('/');
}

function authenticate(email, password) {
  if (email.endsWith('@example.com') && password === 'test') {
    return { email };
  }
}

With our cookie-setting logic in place, let's test it:

  1. Sign in using "test" as the password.

  2. Open DevTools to view cookies.

  3. Notice the "user" cookie storing the email in a URL-encoded JSON format.

The cookie persists even after page reloads, ensuring the authentication state is maintained.

To conditionally display the user's email or the "Sign in" link, we'll read the cookie in the NavBar component.

// File path: components/NavBar.jsx

import { cookies } from 'next/headers';
import NavLink from './NavLink';

export default function NavBar() {
  const userCookie = cookies().get('user');
  const user = userCookie ? JSON.parse(userCookie.value) : null;
  return (
    <nav>
      <ul className="flex gap-2">
        <li className="font-bold font-orbitron">
          <NavLink href="/">
            Indie Gamer
          </NavLink>
        </li>
        <li className="ml-auto">
          <NavLink href="/reviews">
            Reviews
          </NavLink>
        </li>
        <li>
          <NavLink href="/about" prefetch={false}>
            About
          </NavLink>
        </li>
        {user ? (
          <li>
            {user.email}
          </li>
        ) : (
        <li>
          <NavLink href="/sign-in">
            Sign in
          </NavLink>
        </li>
        )}
      </ul>
    </nav>
  );
}
  • Setting Cookies: Done in the server's response headers.

  • Persisting Cookies: Managed by the browser, available in subsequent requests.

  • Reading Cookies: Accessible in server-side components to tailor content based on user authentication status.

Conclusion

By leveraging cookies, we've enhanced our authentication flow to remember user login states across sessions. This allows us to customize the user experience dynamically, showing personalized information in the NavBar. As you explore more, consider setting cookie attributes for security, such as expiration times and domain restrictions.

In the next steps, we'll refine our authentication flow further, exploring how to handle user sessions securely and efficiently. Stay tuned!

Last updated