Blog | G5 Cyber Security

Next.js Authentication: Long Sessions

TL;DR

This guide shows how to handle user authentication in a Next.js application with Server-Side Rendering (SSR) and long session durations. We’ll use cookies for storing session tokens, focusing on security best practices.

1. Choose an Authentication Method

Several options exist: NextAuth.js is popular, but we’ll focus on a simpler approach using JSON Web Tokens (JWTs) and cookies directly for clarity. This assumes you have a backend API to handle user registration/login.

2. Backend API Setup

Your backend needs endpoints for:

Example (Node.js/Express with jsonwebtoken):

const jwt = require('jsonwebtoken');

app.post('/login', async (req, res) => {
  // ... authentication logic...
  if (userIsValid) {
    const token = jwt.sign({ userId: user._id }, 'your-secret-key', { expiresIn: '7d' }); // 7 day expiry
    res.cookie('authToken', token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict' });
    res.json({ message: 'Login successful' });
  } else {
    res.status(401).json({ message: 'Invalid credentials' });
  }
});

Important: Replace 'your-secret-key' with a strong, randomly generated secret.

3. Setting Cookies on Login

When the user successfully logs in via your backend API, set an HTTP-only, secure cookie containing the JWT:

4. Reading Cookies on the Server (SSR)

In Next.js, use getServerSideProps to access cookies during SSR:

export async function getServerSideProps(context) {
  const { req } = context;
  let authToken = req.cookies.authToken;

  if (authToken) {
    try {
      const decodedToken = jwt.verify(authToken, 'your-secret-key');
      // User is authenticated...
      return { props: { user: decodedToken } };
    } catch (error) {
      // Token is invalid or expired...
      console.log('Invalid token:', error);
    }
  }

  return { props: { user: null } }; // User not authenticated
}

Important: Use the same secret key as your backend API.

5. Client-Side Authentication (SPA)

For client-side routes, you can check for the cookie using document.cookie:

function getAuthToken() {
  const cookies = document.cookie.split(';');
  for (let i = 0; i < cookies.length; i++) {
    const cookie = cookies[i].trim();
    if (cookie.startsWith('authToken=')) {
      return cookie.substring('authToken='.length, cookie.length);
    }
  }
  return null;
}

Use this function to determine if the user is logged in and redirect them accordingly.

6. Protecting Routes

Create a custom component or higher-order component (HOC) to protect routes:

7. Session Renewal

To extend session duration without requiring a full re-login:

8. Security Considerations

Exit mobile version