Part 69: Enhancing User Experience with Dynamic Authentication in Next.js

[Pages] Authentication

[Pages] Authentication

In this post, we'll walk through how to integrate user authentication into a Next.js NavBar component, using a server-side API route that fetches user details. This will help us display user-specific information dynamically and improve the overall user experience.

Setting Up the NavBar Component

Our goal is to fetch user data and display it in the NavBar component. We'll achieve this by calling the /api/user route we created earlier. This route reads a JSON Web Token (JWT) from a cookie and queries the CMS for user details.

Step 1: Manage State with useState

First, we need to turn our user variable into a state variable using the useState hook. This allows us to update the component's state dynamically based on user interactions and API responses.

// components/NavBar.js

import Link from 'next/link';
import { useEffect, useState } from 'react';
import { fetchJson } from '../lib/api';

function NavBar() {
  const [user, setUser] = useState(); // Initialize user state

  // Fetch user data when component mounts
  useEffect(() => {
    (async () => {
      try {
        const user = await fetchJson('/api/user');
        setUser(user); // Update user state with fetched data
      } catch (err) {
        // Handle unauthenticated state
      }
    })();
  }, []);

  console.log('[NavBar] user:', user); // Log current user state
  return (
    <nav className="px-2 py-1 text-sm">
      <ul className="flex gap-2">
        {/* NavBar content goes here */}
      </ul>
    </nav>
  );
}

export default NavBar;

Step 2: Fetch User Data with useEffect

We use the useEffect hook to call our API route once the NavBar component mounts. This hook runs the effect only once, thanks to the empty dependency array []. We use an immediately-invoked async function to fetch user data and update the state.

Step 3: Handle Authentication States

Initially, the user variable is undefined since no API request has been made. Once the data is fetched successfully, setUser updates the state. If the API request fails (e.g., due to a 401 Unauthorized error), we keep the state as undefined, indicating that the user is not signed in.

Redirecting After Sign-In

To enhance user experience, we want to redirect users to the HomePage after a successful sign-in. We'll use the Next.js useRouter hook for this purpose.

// pages/sign-in.js

import { useRouter } from 'next/router';
import { useState } from 'react';
import Button from '../components/Button';
import Field from '../components/Field';
import Page from '../components/Page';
import { fetchJson } from '../lib/api';

function SignInPage() {
  const router = useRouter();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [status, setStatus] = useState({ loading: false, error: false });

  async function handleSubmit(event) {
    event.preventDefault();
    setStatus({ loading: true, error: false });
    try {
      const response = await fetchJson('/api/sign-in', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password }),
      });
      setStatus({ loading: false, error: false });
      console.log('sign in:', response);
      router.push('/'); // Redirect to HomePage after successful sign-in
    } catch (err) {
      setStatus({ loading: false, error: true });
    }
  }

  return (
    <Page title="Sign In">
      <form onSubmit={handleSubmit}>
        {/* Form fields and submit button */}
      </form>
    </Page>
  );
}

export default SignInPage;

Testing the Implementation

  1. Initial State: Upon loading, the NavBar logs user: undefined, indicating no user data fetched yet.

  2. Sign In: Use the sign-in form to log in. Upon success, the user is redirected to the HomePage.

  3. Fetching User Data: The NavBar fetches user data after each page load, logging the user details when authenticated.

  4. Session Persistence: Reloading the page retains the session, thanks to the session cookie.

Conclusion

By integrating user authentication into the NavBar component, we improve user experience by dynamically displaying user-specific information. Although this approach involves fetching data on each page load, it ensures that user details are always up-to-date. In future improvements, we could implement caching to optimize performance further. Stay tuned for more on enhancing your Next.js applications!

Last updated