In this guide, we will discuss Next js Protected Routes using a demonstration example application. We will explore how to add guards or protection to the Next js routes so that we can control the access via the AccessContect component in step by step tutorial.
A web application which deals with user data should have protected routes as an essential part to protect unauthorised access to private sections of an application. By protecting the routes, we ensure that only legitimate access is provided to the authenticated users’ access application. This plays an important role to maintain the security and integrity of users’ data.
[lwptoc numeration=”decimal” numerationSuffix=”none”]
What are Next.js Protected Routes?
A route in a front-end application refers to a specific URL pattern which an application refers to display a specific component and sites related template or view. For example, we may have /posts or /posts/:id route in our blogging web application to display all or single posts based on the route pattern.
A protected route is a route that is only accessible to users who are authenticated properly by using any type of authentication system which is mainly server-side. If a user who is not authenticated tries to access a protected route, they will be redirected to the login page or receive an error message.
In Next js, we can create protected routes in various ways, such as:
- Using a higher-order component (HOC)
- Using Next.js middleware
- Using
getServerSideProps
orgetStaticProps
.
The Role of Authentication and Authorization in Protected Routes
Authentication and authorization are two important concepts that play an important role in the context of protected routes:
Authentication
During the login process, a user enters their credentials including username/email and password. Then the application checks and verify these details by communicating with the database. this process is called Authentication.
Authorization
After a user is verified and allowed to enter the web app, the user’s profile is checked to grant or deny access to various parts of an application. For some users, only a few sections are accessible for example visitors, but admin-type users can access all parts. This process of deciding user access is called authorization.
To implement protected routes in an application, both authentication and authorization work concurrently to ensure that only authenticated and authorized users can access certain routes.
Protected Routes in Next.js vs React Router
Both Next.js and React Router allow the creation of protected routes but the way they handle it is narrowly different.
The React Router library is used to create protected routes typically a PrivateRoute
component that checks user authenticity totally on the client side. If the user is authenticated then the PrivateRoute
component will render the specified route, else the user is redirected to the login screen.
On the other hand Next js supports both client-side and server-side rendering. This means you can check if a user is authenticated on the server-side before sending any HTML to the client. This can provide a better user experience as the user won’t see any flash of content that they are not authorized to view.
How to Implement Protected Routes in Next.js?
Follow these quick steps to set up protected routes in the Next js application:
Step 1 – Create Next js Application
Step 2 – Setup AuthContext
Step 3 – Using AuthContext in Protected Dashboard Page
Step 4 – Update Index Page
Step 1 – Create Next js Application
First, we will create a new Next js application executing the below command in the terminal:
npx create-next-app@11 protected-route-app
Enter into the application folder:
cd protected-route-app
Finally, start your Next.js application by running the following command:
npm run dev
Your Next.js application is now up and running you can view it by navigating to http://localhost:3000
in your web browser.
Step 2 – Setup AuthContext
The authContext
is an important part of implementing protected routes in Next js. The authContext holds our authentication state and provides functions to log in and log out.
First, create a new file named AuthContext.js under context folder at the root of your project and update it with the following code:
//./context/AuthContext.js
import { createContext, useState, useEffect } from "react";
import cookies from "js-cookie";
import { useRouter } from "next/router";
export const AuthContext = createContext();
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [isAuthorized, setIsAuthorized] = useState(true);
const router = useRouter();
useEffect(() => {
cookies.set("isAuthorized", JSON.stringify(isAuthorized));
}, [isAuthorized]);
function login() {
const user = { name: "John Doe" };
cookies.set("user", JSON.stringify(user));
setUser(user);
router.push("/dashboard");
}
function logout() {
cookies.remove("user");
cookies.remove("isAuthorized");
setUser(null);
setIsAuthorized(true);
router.push("/");
}
function toggleAuthorize() {
setIsAuthorized(!isAuthorized);
}
return (
<AuthContext.Provider
value={{ user, login, logout, isAuthorized, toggleAuthorize }}
>
{children}
</AuthContext.Provider>
);
}
We have a provider component name AuthProvider
that will wrap up our application and provide the authentication state and functions.
Thereafter go to the ~pages\_app.js file and wrap the application with the AuthProvider
as shown below:
import { AuthProvider } from "../context/AuthContext";
function MyApp({ Component, pageProps }) {
return (
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
);
}
export default MyApp;
Step 3 – Using AuthContext in Protected Dashboard Page
Now, we will create a sample protected page named Dashboard as this path ~pages\dashboard.js and update it as below:
import { useContext } from "react";
import { AuthContext } from "../context/AuthContext";
export default function Dashboard({ user }) {
const { logout, isAuthorized, toggleAuthorize } = useContext(AuthContext);
if (!isAuthorized) {
alert("You are not authorized to view this page.");
return null;
}
return (
<div>
<h1>Welcome, {user.name}!</h1>
<button onClick={logout}>Log out</button>
</div>
);
}
export async function getServerSideProps(context) {
const { user, isAuthorized } = context.req.cookies;
if (!user || JSON.parse(isAuthorized) === false) {
return {
redirect: {
destination: "/",
permanent: false,
},
};
}
return {
props: { user: JSON.parse(user) },
};
}
The most important part is we used the page protection login inside the getServerSideProps
hook which runs on the server side before the page is rendered. We can use this function to check if a user is authenticated before rendering a page.
What is
useContext
?The
useContext
is a built-in React hook which allows to access the value of a context. In React, Context is a way to pass data across the components without any need to pass via props manually at every level. It’s designed to share data that can be considered “global” for a tree of React components, such as the current authenticated user, theme, or preferred language.
Step 4 – Update Index Page
Finally, we will update the ~pages\index.js file to have two buttons, one for Login and the other will help users to control the Authorize and Unauthorize state of a user for testing purposes.
Update the file as shown below:
import { useContext } from "react";
import { AuthContext } from "../context/AuthContext";
export default function Home() {
const { login, isAuthorized, toggleAuthorize } = useContext(AuthContext);
return (
<div>
<h1>Login Page</h1>
<button onClick={login}>Log in</button>
<button onClick={toggleAuthorize}>
{isAuthorized ? "Unauthorize" : "Authorize"}
</button>
</div>
);
}
Users can click on the Login button to redirect the Dashboard page if the second button is set to Authorized, otherwise
Conclusion
We have built a simple Next.js application to demonstrate the concept of protected routes which are an essential part of any web application that requires user authentication.
We used React’s Context API to manage the global state which we used to manage the authentication state of the user. We also used cookies to persist the authentication state across sessions to ensure the user remains logged in even if the app is refreshed.
We deployed the getServerSideProps
function to protect our routes on the server side and redirect unauthenticated users before the page is even rendered.
Lastly, we used the useRouter
hook from Next.js to programmatically navigate the user to different pages. This application is a simplified example and does not include actual authentication. But it can be a good start to use these concepts in a more advanced way according to your application requirements.
Leave a Reply