Next.js Authentication using Higher-Order Components
·7 min read
Table of Contents
Introduction
Managing authentication in Next.js is quite tricky, with problems such as content flashing. In this blog, I won't address the problems and explain how to solve it in detail, because I've written a blog about that in Next.js Redirect Without Flashing Content.
In this blog, I'll cover how to handle them cleanly using Higher Order Components.
The Usual Way & The Problem
Usually for the authentication in Next.js, we define routes that need to be blocked like so:
Then we have a component that checks the route like this:
This works, but there are several problems:
It's not colocated, the placement of authentication is not located in the page itself, instead in another component such as PrivateRoute
Error Prone, when you're doing route changes, for example: if you're moving the pages/blocked-component.tsx file to pages/blocked/component.tsx, you will have to change the protectedRoutes variable into the new route.
This is quite dangerous because with the protectedRoutes variable, there are no type checking because there is no way for TypeScript to know if that's the right path. (maybe soon)
Higher-Order Component
My friend and I built a higher-order component that we can put inside the page like so:
With this implementation, it's now colocated within the page and it won't be a problem if you change the file name.
Adding Several Types of Pages
In my experience of building simple authenticated apps, there are 3 type of authenticated pages that we need to support
For the demo, you can try it yourself on theFor the demo, you can try it yourself on theFor the demo, you can try it yourself on theFor the demo, you can try it yourself on theFor the demo, you can try it yourself on the demo page
1. Simple Protected Pages
It's for pages that need protection, such as dashboard, edit profile page, etc.
Behavior
Unauthenticated users will be redirected to LOGIN_ROUTE (default: /login), without any content flashing
Authenticated users will see this page in this following scenario:
Direct visit using link → user will see a loading page while the withAuth component checks the token, then this page will be shown
Visit from other pages (router.push) → user will see this page immediately
2. Authentication Pages (Login)
It's for pages such as Login and Register or any other page that suits with the behavior.
Behavior:
Unauthenticated users can access this page without any loading indicator
Authenticated users will be redirected to HOME_ROUTE (default: /).
We're assuming that authenticated users won't need to see login anymore. Instead, they should be redirected to the HOME_ROUTE.
It's also best to hide all links back to the login page when the users is already authenticated.
3. Optional Page
This is a more specific use case, but sometimes there are pages that you don't need to be authenticated to visit, but you still need to show the users details if they are authenticated.
Behavior:
This page is accessible to all users
You can get the user from useAuthStore.useUser()
Page Focus Synchronization
We also added a page focus listener. When you open several tabs, the authentication will be synced across tabs.
Source Codes
We use Zustand to store authentication data globally
Zustand Store
withAuth HOC Component
For more code and implementation examples check out the code on GitHub
Next Auth, for the inspiration and the idea of using HOC to handle authentication.
Conclusion
This will be a great addition to your code, making it cleaner and more efficient. You should colocate your code as much as possible, and this will be a step to do that.