How to redirect back to private route after login in Next.js?

I am building a Next.js project where I want to implement private route similar to react-private route. In React this can be done by using react-router, but in Next.js this cannot be done. next/auth has the option to create private route I guess, but I am not using next/auth.

I have created a HOC for checking if the user is logged-in or not, but I'm not able to redirect the user to the private he/she wants to go after successfully logging in. How to achieve this functionality in Next.js? Can anybody help me in this?

This is the HOC, I used the code from a blog about private routing.

import React from 'react';
import Router from 'next/router';

const login = '/login'; // Define your login route address.

/**
 * Check user authentication and authorization
 * It depends on you and your auth service provider.
 * @returns {{auth: null}}
 */
const checkUserAuthentication = () => {
  const token = typeof window !== "undefined" && localStorage.getItem('test_token');
  if(!token) {
    return { auth: null };
  } else return {auth:true};
   // change null to { isAdmin: true } for test it.
};

export default WrappedComponent => {
  const hocComponent = ({ ...props }) => <WrappedComponent {...props} />;

  hocComponent.getInitialProps = async (context) => {
    const userAuth = await checkUserAuthentication();

    // Are you an authorized user or not?
    if (!userAuth?.auth) {
      // Handle server-side and client-side rendering.
      if (context.res) {
        context.res?.writeHead(302, {
          Location: login,
        });
        context.res?.end();
      } else {
        Router.replace(login);
      }
    } else if (WrappedComponent.getInitialProps) {
      const wrappedProps = await WrappedComponent.getInitialProps({...context, auth: userAuth});
      return { ...wrappedProps, userAuth };
    }

    return { userAuth };
  };

  return hocComponent;
};

This is my private route code:

import withPrivateRoute from "../../components/withPrivateRoute";
// import WrappedComponent from "../../components/WrappedComponent";

const profilePage = () => {
  return (
    <div>
      <h1>This is private route</h1>
    </div>
  )
}

export default withPrivateRoute(profilePage);

To redirect back to the protected route the user was trying to access, you can pass a query parameter with the current path (protected route path) when redirecting to the login page.

// Authentication HOC
const loginPath = `/login?from=${encodeURIComponent(context.asPath)}`;

if (context.res) {
    context.res.writeHead(302, {
        Location: loginPath
    });
    context.res.end();
} else {
    Router.replace(loginPath);
}

In the login page, once the login is complete, you can access the query parameter from router.query.from and use that to redirect the user back.

// Login page

const login = () => {
    // Your login logic
    
    // If login is successful, redirect back to `router.query.from` 
    // or fallback to `/homepage` if login page was accessed directly
    router.push(router.query.from && decodeURIComponent(router.query.from) ?? '/homepage');
}

Note that encodeURIComponent/decodeURIComponent is used because the asPath property can contain query string parameters. These need to be encoded when passed to the login URL, and then decoded back when the URL is used to redirect back.