ReactHustle

NextJS Redirect Without Flashing Content

Jasser Mark Arioste

Jasser Mark Arioste

NextJS Redirect Without Flashing Content

Hello hustlers. In this tutorial, you'll learn how to use a server-side redirect to prevent the flashing of content for unauthenticated users. We'll use NextJS Middleware along with the next-auth package for authentication.

Prerequisites #

This guide assumes the following:

  1. You're using NextJS v12.3.4 and above. This gives us the best middleware functionality.
  2. You're using next-auth v4.17 and above. 

Problem with Static Pages #

If you're using next-auth and you have static pages in your app, you can only get the session from the client-side. Sometimes, this creates a delay in getting the user and shows flashing content if not implemented properly:

import { NextPage } from "next";
import { signOut, useSession } from "next-auth/react";
import React from "react";
const HomePage: NextPage = () => {
  const { data } = useSession();
  if (!data?.user) {
    return <div>Unauthorized - 403. Please login</div>;
  }
  return (
    <div>
      <h1>Home Page</h1>
      <p>You are logged in as {data?.user?.email} </p>
    </div>
  );
};
export default HomePage;
12345678910111213141516

Another problem with this approach is that we have to add this logic to every page that needs authentication.

This flashing doesn't occur in server-side generated pages since we can check the session inside getServerSideProps and redirect to the login page as necessary:

Inside a page component:

// pages/admin.tsx
import { GetServerSideProps } from "next";
import { getSession, useSession } from "next-auth/react";
import { GetServerSideProps } from "next";
import { getSession, useSession } from "next-auth/react";
import React from "react";
const AdminPage = () => {
  const { data } = useSession();
  if (!data?.user) {
    return <div>Unauthorized - 403. Please login</div>;
  }
  return <div>AdminPage</div>;
};
export default AdminPage;

export const getServerSideProps: GetServerSideProps = async (ctx) => {
  const session = await getSession({ req: ctx.req });
  if (!session) {
    return {
      redirect: {
        destination: "/login",
        permanent: false,
      },
    };
  }
  return {
    props: {
      session,
    },
  };
};
12345678910111213141516171819202122232425262728293031

Inside _app.tsx:

import "../styles/globals.css";
import type { AppProps } from "next/app";
import { SessionProvider } from "next-auth/react";

function MyApp({ Component, pageProps }: AppProps) {
  const { session, ...restPageProps } = pageProps;
  return (
    <SessionProvider session={session}>
      <Component {...restPageProps} />
    </SessionProvider>
  );
}

export default MyApp;
1234567891011121314

This prevents flashing the unauthorized content since the session is provided via props and the client does not have to make a request using /api/auth/session. The problem with this approach is that, you'll have to add this logic for every protected page in your application.

How can we improve on this?

The Solution #

Since NextJS v12+, we have the ability to process the incoming request before returning the generated page (static or server-side generated). 

Create a middleware.ts file at the root directory of your project and add this logic here:

// middldware.ts
import { getToken } from "next-auth/jwt";
import { NextRequest, NextResponse } from "next/server";
export async function middleware(req: NextRequest) {
  const pathname = req.nextUrl.pathname;
  const protectedPaths = ["/", "/admin"];
  const isPathProtected = protectedPaths?.some((path) => pathname == path);
  const res = NextResponse.next();
  if (isPathProtected) {
    const token = await getToken({ req });
    if (!token) {
      const url = new URL(`/login`, req.url);
      url.searchParams.set("callbackUrl", pathname);
      return NextResponse.redirect(url);
    }
  }

  return res;
}
12345678910111213141516171819

Demo and Code #

The demo is available at Vercel and the full code is available on GitHub.

Conclusion #

We learned how to redirect without flashing content by using NextJS middleware. Middleware is a very powerful feature in NextJS and there's a lot we can do to process the incoming request.

If you like this tutorial, please leave a like or share this article. For future tutorials like this, please subscribe to our newsletter or follow me on Twitter.

What's Next? #

  1. Add role-based authorization for your NextJS app. Differentiate normal users from admin users and what pages they can access.
  2. Implement middleware chaining/stacking. Organize your middleware functions like a pro.
Share this post!

Related Posts

Disclaimer

This content may contain links to products, software and services. Please assume all such links are affiliate links which may result in my earning commissions and fees.
As an Amazon Associate, I earn from qualifying purchases. This means that whenever you buy a product on Amazon from a link on our site, we receive a small percentage of its price at no extra cost to you. This helps us continue to provide valuable content and reviews to you. Thank you for your support!
Donate to ReactHustle