NextAuth.js Page Guards


Updated Jul 4th, 2023

This post Here are some notes from a course section on the process.

Overall there is more than one approach. There is at least three.

1.) In getServerSideProps as server-side page guard (Seen in Learn-trivia project in the addCategory and addQuestion components).
2.) In a useEffect to make sure a user is logged in (as originally seen in pages/admin, pages/auth, pages/profile.) This is a client-side page guard and creates a flashing state.
3.) In API routes to make sure the a user is logged in. As seen in “/api/allQuestions” route, (api-route protection).

Is using a combo of two approaches, say the API and server-side approach overkill that should really be avoided since it affects performance?

A Note on v4

This post was written based on v3 implementations. There are some minor changes to upgrading to v4 but one of the bigger ones for me was protecting API routes using the “getServerSession” function instead of “getSession.” The “getServerSession” function requires passing in, not only the request, but the response and an “authOptions” object that required tweaking my existing […nextauth].js implementation including a move to TypeScript.

import { getServerSession } from "next-auth/next"
import { authOptions } from "../api/auth/[...nextauth]"

  const session = await getServerSession(req, res, authOptions)
    if (!session) {
      return res.status(401).json({ message: "Not authenticated" })
    if (!session.user) {
      res.status(401).json({ message: "Not authenticated" })

From the docs: “This method can drastically reduce response time when used over getSession on server-side, due to avoiding an extra fetch to an API Route”

Read more here

Admin Page

I originally implemented approach number one an Admin page to manage all CRUD operations for a collection of trivia questions. The problem was the flashing was really bad.


The “useSession approach” was implemented for the navbar and that took forever to calculate resulting in a very delayed jump in navbar list items. Not ideal at all.

Tone Down Loading State

You can better manage the loading state to tone down the change that happens when the data coming in. Avoid any major shift with spacers or dummy data.

Getting the Data in GSSP

Instead of calling an internal api, you can call the functions to connect and query the DB directly from inside the GSSP function. This is fine except I was running into an issue re-using the same client since in the “getCategories” function the client is then closed. So I connect to DB, get Categories, Close the Connection then need to connect again and “getAllQuestions” and then close again.

I’m hesitant to not close the db connection in the db function files because I’m not sure if other code is depending on this behavior. Brings to light what is the best strategy. I ripped out the closing in the db function files just to prove the code then worked, which it did. Do you need to close the client at all, and if so, where is the best place to close it, (in the actual functions or when calling them)?

Remember this note from Max: “In this course, we always close our MongoDB connections via client.close(). This works and you can do that. If you build an application where your MongoDB-related code will execute frequently (e.g. the API route will be hit frequently), you might want to take advantage of MongoDB’s “connection pooling” though. For this, simply remove all client.close() calls from your code. The connection will then NOT be closed and will be re-used across requests.”

Reloading the Page

It’s the re-running the GSSP code without a full page refresh that can sometimes be a probelm.

The Solution

Implementing the server-side page guard with getSession in a GSSP function is a piece of cake. Calling the db functions inside of GSSP required a little tweaking but was also pretty simple. Remember you need to use the “toString” method on the MongoDB ids.