How to implement authentication for SSR pages & API routes in Next.js

Full-stack apps built with Next.js has three aspects of authentication: client-side authentication, server-side authentication, and API route authentication. I have discussed client-side authentication in a previous post. In this post, I will be discussing Server-side & API routes authentication in NextAuth.js.

How does server-side authentication work?

  1. The browser sends a request with a user session to a server-side page on Next.js App
  2. The server-side rendered page sends a request to the backend API to authenticate the session
  3. If authentication is successful, the server pre-rendered the requested page
  4. Otherwise, redirect the user to the login page( for example )

Let us understand server-side authentication with an application

Setting up the App

If you are reading this post for the first time, please read “How to set up authentication on the client-side in Next.js” first. Please make sure to read the following sections.

  • Authentication with NextAuth
  • Setting up the app
  • Adding Authentication provider
  • Setting up AuthNext for Authentication
  • Handing events in UI
  • UseSession hook

After you read the above sections, please replace the code in dashbaord.js with the following code.

import { getSession } from "next-auth/react";
import Styles from '../styles/Home.module.css';


export default function Dashboard({ user }){   

      return(
      <div>
            <h2>This is the dasboard</h2>           
            <p className={ Styles.nav_button }>{ user.name }</p>
            <p className={ Styles.nav_button }>{ user.email }</p>

      </div> 
      )

  } 


export async function getServerSideProps( context ){

    const session = await getSession( context );

//protecting the http://localhost:3000/dashboard route
if( !session ){
    return{
        redirect:{
            destination:`api/auth/signin?callbackUrl=${ process.env.REDIRECT_URL }`,
            permanent: false,
        }
    }
}else{
    const { user } = session;

    return {

        props:{
            user
        }
    }
}
}

In the above code, getServerSideProps runs in the server with every request you make. The client (the browser ) sends a request and this request is passed to the context parameter. We use the getSession function to retrieve session information. You must pass the context as a parameter to this function.

If the session is available, we get the user information from the session, otherwise, we redirect the user to the Sign In page.

The getServerSideProps function returns an object. The redirect is one of the props of this object. The redirect prop itself is another object with destination and permanent properties. The destination property specifies the path you route to. I have placed callbackUrl in an environment variable in .env.locale. The permanent property is to tell the browser and search engines if a redirect should be cached or not. In this, case it is not cached.

If a session is available, extracted information from the session is passed to the React component. Then, the pre-rendered pages will be sent to the browser to display.

Note:

NextAuth.js recommends unstable_getServerSession retrieving the session. However, unstable_getServerSession is still experimental at the moment of writing this post. Therefore, I will not be using this function.

Modify env.locale

In your .env.locale add the following variable

REDIRECT_URL=http://localhost:3000/login

Now, enter http://localhost:3000/dashboard in the browser. You will be redirected to the Sign In page if you have not signed in on the home page, which is at http://localhost:3000/

Securing API routes

We have learned so far about authentication on the client-side, and server-side, and how to secure pages on the client-side and server-side. Now, let’s look at how to secure the API routes.

Create a file name secure-session.js in pages/api

Add the following code

pages/api/secure-session.js

import { getSession } from "next-auth/react";


export default async function handler( req, res ){
    const session = await getSession({ req });

    if( !session ){
        res.status( 401 ).json( { error: 'Anauthenticated User'})
    }else{
        res.status( 200 ).json( { message:'success' , session })
    }
}

The code here is easy to understand. You will get the session with the getSession function and send the response accordingly.

Summary

Authentication is a critical aspect of web applications. Next.js fulfill it by securing pages in client-side, server-side, and auth routes. Having an understanding of data-fetching methods is important when choosing and applying authentication patterns in Next.js.