DEV Community

Cover image for How to implement protected routes in Next.js

How to implement protected routes in Next.js

Caleb O. on March 05, 2022

One of the features that is neccessary in a single page application as it pertains to the authentication or its security is the ability to conditio...
Collapse
 
caseychoiniere profile image
Casey Choiniere

Just a little feedback on some things that you might want to correct in your article so that people are not misled.

The isUserAuthenticated function will never return true. It will return "false" or "undefined". Instead of what you have:

const isUserAuthenticated = () => {
if (!authState.token) {
return false;
}
};

You might want to consider simply:

const isUserAuthenticated = () => !!authState.token;

Which will always return a boolean value.

Also, where you're checking if the user is authenticated in your useEffect you have your logic backwards. If the user isn't authenticated you're sending them to the dashboard, not the login page.

You have this:
React.useEffect(() => {
// checks if the user is authenticated
authContext.isUserAuthenticated()
? router.push("/")
: router.push("/dashboard");
}, []);

Which should be:
React.useEffect(() => {
// checks if the user is authenticated
authContext.isUserAuthenticated()
? router.push("/dashboard")
: router.push("/");
}, []);

Collapse
 
seven profile image
Caleb O.

Dang!!!

Thank you so much for pointing this out. I'll make the necessary change. Thank you once again for your feedback man!

Collapse
 
kthehatter profile image
Ahmed Khalil YOUSFI

you still haven't updated your article

Thread Thread
 
seven profile image
Caleb O.

All done!

Thank you for reminding me

Thread Thread
 
ajitpatil92002 profile image
Ajitpatil92002

Yghhh

Collapse
 
mdfaizanahmed786 profile image
Mohammed Faizan Ahmed

thank you for this article.

Collapse
 
seven profile image
Caleb O.

I'm glad you found it helpful

Collapse
 
ajitpatil92002 profile image
Ajitpatil92002

Hhh

Collapse
 
hidaytrahman profile image
Hidayt Rahman

Nice Article, But why we are not using session ?

Collapse
 
seven profile image
Caleb O.

Thanks Hidayt!

Funny enough. This was when I first laid my hands on auth in Next.js. Now that I've been accustomed to it. I'm using cookies and session with getServerSideProps

Hopefully, I'll have an article about it and share it Herr, soon.

Collapse
 
adeleke5140 profile image
Kehinde Adeleke

Hi Caleb, do you have any open source repo demonstrating your use of cookies and session with getServerSideProps?

Thread Thread
 
seven profile image
Caleb O.

Hi Kehinde,

At the moment, No. But, I'm experimenting with cookies and getServerSideProps currently.

I'm using nookies (a Next.js cookie helper package) to parse cookies on the client and server.

Perhaps and when it turns out well. I'll share what I learned.

Collapse
 
matejvykoukal profile image
Matej Vykoukal

Maybe I am wrong, but is it safe to store token in localStorage? AFAIK localStorage can be accesed by 3rd party scripts :/

Collapse
 
seven profile image
Caleb O.

You're absolutely correct.

Storing JWT in localStorage isn't the perfect solution. You can try keeping the token in a cookie.

Whatever works best for everyone's use-case.

Collapse
 
alex067 profile image
Alexandros Panayi

I feel like useEffect is the wrong hook to use. You're rendering all your components, then checking if the user is authenticated.

Wouldn't it be better just to:

!authContext.isUserAuthenticated() && router.push("/")

Outside of the useEffect?

Collapse
 
tejaswan profile image
Tejaswan Kalluri

can we use useLayoutEffect() hook. which runs before the rendering part.

youtu.be/sRDUOd1IkS8

Collapse
 
devmuhnnad profile image
Muhnnad Habib

Thank you for this article, but I just got confused a little bit, you didn't use localstorage.getItem at all!, this means whenever the user land on the page he will be not authorized even though the token exists in the localstorage? am I wrong?

Collapse
 
seven profile image
Caleb O.

Hi Muhnnad,

I'm glad you found it helpful. I'm not using the getItem method here because all I'm doing here is to check if the user's auth token is in localStorage.

If it is, authenticate the user. If it isn't, re-route them to the login page.

Hence, the need for this snippet, and the one below, in the use Effect hook.

const isUserAuthenticated = () => !!authState.token;
Enter fullscreen mode Exit fullscreen mode
Collapse
 
amandeep2603 profile image
Aman Deep

isUserAuthenticated won't work becasue next js have by default ssr. Here's simple solution that put jwt in cookie. it will work otherwise , it will show undefined.

Collapse
 
mahanjs profile image
mahan-js

Ok

Collapse
 
mahanjs profile image
mahan-js

Ok

Thread Thread
 
mahanjs profile image
mahan-js

Ok

Thread Thread
 
mahanjs profile image
mahan-js

Ok

Thread Thread
 
mahanjs profile image
mahan-js

Ok

Collapse
 
hidaytrahman profile image
Hidayt Rahman

Have covered session here.
Handle Protected Route using Session

Collapse
 
seven profile image
Caleb O.

Great! I see that you're using next-auth here too.

My own case would be for an external backend. Thank you for sharing though.

Collapse
 
hidaytrahman profile image
Hidayt Rahman

It works with both cases internal and external backend by using next-auth

Thread Thread
 
seven profile image
Caleb O.

Oh! Great!

Collapse
 
rabbyhossain profile image
Rabby Hossian

If you have hundreds of pages, there will be a lot of code duplication with this approach

Collapse
 
seven profile image
Caleb O.

What would the best approach look like?

Collapse
 
liv_it profile image
liv • Edited

You can create a new function inside your auth-context.js like this.

export const ProtectRoute = ({ children }: any) => {
    const router = useRouter();
    const authContext = React.useContext(AuthContext);

    const isLoggedIn = authContext.isUserAuthenticated();

    if (isLoggedIn && window.location.pathname === "/") {
        router.push("/dashboard");
    } else if (!isLoggedIn && window.location.pathname !== "/") {
        router.push("/");
    }

    return children;
};
Enter fullscreen mode Exit fullscreen mode

And then use it as a wrapper to your pages.

Example in MyApp component, like this:

const MyApp = ({ Component, pageProps }) => {
  return (
   <AuthProvider>
     <ProtectRoute>
        <Component {...pageProps} />
      </ProtectRoute>
    </AuthProvider>
  )
}
Enter fullscreen mode Exit fullscreen mode

Alternatively, you can also add this to any individual page.

export default const ProtectedPage = () => {
  return (
    <ProtectRoute>
      <!-- contents of the page -->
    </ProtectRoute>
  )
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
seven profile image
Caleb O.

Thank you for sharing this @liv_it