Protecting Routes from unauthenticated users is a crucial part of any app.
In this blog, I'll show you exactly how to do that with your NextJS pages using Higher-Order Components. [1]
There can be several ways of authenticating a user like using cookies or JWT tokens.[2]
I'll be using JWT token as an example, where the accessToken is stored in the localStorage
Let's consider a page "/dashboard". This page should be only accessed by authenticated users
In our Dashboard.jsx
// pages/dashboard.jsx
import withAuth from "HOC/withAuth.js";
const Dashboard = ({ user }) => {
return (
<div>
<h1>Dashboard</h1>
<h2>{user.name}</h2>
</div>
);
};
export default withAuth(Dashboard);
Notice that we are importing withAuth.jsx and exporting the page by passing it as an argument. That is all we need to do for our pages.
In our withAuth.jsx
I'll show you two methods of implementations:
- Method 1: We don't verify the token
- Method 2: We verify the token
Method 1: (We don't verify the token)
// HOC/withAuth.jsx
import { useRouter } from "next/router";
const withAuth = (WrappedComponent) => {
return (props) => {
// checks whether we are on client / browser or server.
if (typeof window !== "undefined") {
const Router = useRouter();
const accessToken = localStorage.getItem("accessToken");
// If there is no access token we redirect to "/" page.
if (!accessToken) {
Router.replace("/");
return null;
}
// If this is an accessToken we just render the component that was passed with all its props
return <WrappedComponent {...props} />;
}
// If we are on server, return null
return null;
};
};
export default withAuth;
Method 2: We need to verify the token.
// HOC/withAuth.jsx
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
// the below function could be any of your custom implementation for verifying the token. I've added it as means of explanantion
import verifyToken from "services/verifyToken";
const withAuth = (WrappedComponent) => {
return (props) => {
const Router = useRouter();
const [verified, setVerified] = useState(false);
useEffect(async () => {
const accessToken = localStorage.getItem("accessToken");
// if no accessToken was found,then we redirect to "/" page.
if (!accessToken) {
Router.replace("/");
} else {
// we call the api that verifies the token.
const data = await verifyToken(accessToken);
// if token was verified we set the state.
if (data.verified) {
setVerified(data.verified);
} else {
// If the token was fraud we first remove it from localStorage and then redirect to "/"
localStorage.removeItem("accessToken");
Router.replace("/");
}
}
}, []);
if (verified) {
return <WrappedComponent {...props} />;
} else {
return null;
}
};
};
export default withAuth;
Footer
Wasn't that easy!
I hope this blog helped you. If you got any queries or feedback then let me know 😀
Latest comments (35)
Please what is inside here??
import verifyToken from "services/verifyToken";
Hey, There is nothing inside of it.
I've added it as a way of showing the usage.
In your case, it could be any function that would verify your token.
Thanks a lot Shubham!
Thank you for the post. But it is not working in nextjs 12
useRouter hook is called conditionally
Error: Component definition is missing display name.
I received this error while using the component verifying the accessToken.
Thanks for the article. I'm using
" next ":" ^ 12.0.4 ",and I don't have access to localStorage or cookies, do you have any idea what that might be?localStorage is in the browser. Every modern browser has local storage
Thanks a lot for this post its very helpful.
i am facing an issue when wrapping my page withAuth, it loads the page then redirects to "/" or whatever my fallback is, is there a way to prevent that from happening.
You could try removing the Router.replace("/"), by returning some JSX like "Verifyiing" or something
So I have tried this . Eventually an issue arose which was the type of window is undefined on rendering and it returns null . so nothing gets loaded . My screen is empty and my web app freezes.
Edit: This won't works
If u using getServerSideProps, when you view page source then it not have any content, not friendly SEO 😥 Can u fix that?
Hello, in case of it not working with getServerSideProps, I believe it doesn't matter. Because search engines can't crawl protected routes anyway (the search engine doesn't have a username/password for your application). Basically, any page you need to pass a login screen in order to view won't be crawled by a search engine spider anyway. In other words, don't wrap any publicly viewable (and therefore search engine crawlable) pages with WithAuth() in order to avoid trouble with SEO. :)