How to Protect Routes With React Router v6 (Old APIs)
Tags: protectedroute, reactrouter, webdev, react
Published: 2023-09-16 05:22:52

## Table of Content

- Getting Started
- Cloning and setting up the project
- Creating paths with React Router and making components
- Protecting the Dashboard path and preventing accessing the sign-in and sign-up path
- Demo Video
- Conclusion

## Getting Started

Hey folks! In this blog, I'll share how to create a protected route with React Router 6. 

I have a Demo app, which has three paths, the home, the sign-in, and the dashboard path. The dashboard will be the protected path that only the authenticated user can access. If a non-authenticated user tries to access it they will navigate to the sign-in path.

I have initialized my project with the Vite React template. I have provided the source code below, go to that URL and clone the project if you want to play around with the code.

## Cloning and setting up the project

1. Go to this URL: https://github.com/muditchoudhary/my-demo-app
2. Fork and then clone the project locally
3. `cd my-demo-app` 
4. Run `npm install` - Will download the necessary packages
5. Then start the server `npm run dev` - will run the dev server

## Creating paths with React Router and making the four pages

I have created one `RootLayout` which will be the parent layout for all of the other 3 route pages. Then I created three routes and pages.

```jsx
import { Routes, Route, BrowserRouter } from "react-router-dom";

import { HomePage } from "./pages/HomePage";
import { RootLayout } from "./layouts/RootLayout";
import { SignInPage } from "./pages/SignInPage";
import { DashBoardPage } from "./pages/DashBoardPage";

function App() {
	return (
		<>
			<BrowserRouter>
				<Routes>
					<Route path="/" element={<RootLayout />}>
						<Route index element={<HomePage />} />
						<Route path="/sign-in" element={<SignInPage />} />
						<Route path="/dashboard" element={<DashBoardPage />} />
					</Route>
				</Routes>
			</BrowserRouter>
		</>
	);
}

export default App;

```
The code of pages is very simple, `HomePage` has a `h1` heading. The `SignInPage` has a form with an `onSubmit` handler that will call the `signIn` method to store user details locally in the `LocalStorage`. And the `DashBoardPage` has an `h1` heading.

## Protecting the Dashboard path and preventing accessing the sign-in path after sign-in

Currently even without sign-in the user can access the `/dashboard` path. And after the sign-in, they can access the `/sign-in` path. This is bad user experience. We want to prevent the user from accessing the `/dasboard` path without sign-in and prevent accessing the `/sign-in` path after sign-in. 

To do this we will create a wrapper router component that will check if the user has signed in when visiting the `/dashborad`. We will create another wrapper component that will check if the user has already signed in and then prevent accessing `/sign-in` path.


## Protecting the DashBoard

In the App.jsx I have created an `AuthGuard` component which acts as a wrapper or parent element for the `/dashboard` path. It gets the user object from the `LocalStorage`, and checks if the user is null or not. If null it navigates to the sign-in path along with the `form` state to remember where the user wants to go. So that after sign-in the user is redirected to that path instead of home.

```jsx
const AuthGuard = () => {
	const user = JSON.parse(localStorage.getItem("user"));
	const location = useLocation();

	if (user === null) {
		return <Navigate to="/sign-in" state={{ from: location }} replace />;
	} else {
		<Outlet />;
	}
};
```

```jsx
<>
			<BrowserRouter>
				<Routes>
					<Route path="/" element={<RootLayout />}>
						<Route index element={<HomePage />} />
						<Route path="/sign-in" element={<SignInPage />} />
						<Route element={<AuthGuard />}>
							<Route
								path="/dashboard"
								element={<DashBoardPage />}
							/>
						</Route>
					</Route>
				</Routes>
			</BrowserRouter>
		</>
```

## Preventing accessing sign-in path after sign-in

After the the user has signed in we do not want the user to be able to access the sign-in path. To prevent this I created an `AuthRedirect` component wrapper which gets the user from `LocalStorage` and if it is **not null** navigates the user to the `home` path. And If it is null it lets the sign-in component render.

```jsx
const AuthRedirect = () => {
	const user = JSON.parse(localStorage.getItem("user"));
	if (user === null) {
		return <Outlet />;
	} else {
		return <Navigate to={"/"} replace />;
	}
};
```

```jsx
<Route element={<AuthRedirect />}>
    <Route path="/sign-in" element={<SignInPage />}/>
</Route>

```
**Note**: Navigating the user to the `home` path is not a good user experience. Currently, I do not know how to remember the previous path from which the user goes to the sign-in path. For example. When the user is in the `/dashboard` path instead of navigating to the `home` path we should navigate back to the `dashboard` path. 

If you know how to do it, please tell me in the comments. Otherwise, I'll update the blog when I find and understand.

## Demo Video

https://imgur.com/a/oENS6ty

## Conclusion

That is how we prevent the user from navigating the protected route in the front end. In a real application or project, you will not directly access the `LocalStorage`. Instead, you will possibly have a global context that first checks the user in `LocalStorage`, and when the user signs in it update that context.

Thank you! If you like it make sure to give a like and share it if you want. If you have any doubts you can ask me in the comments.

Here are my socials you can connect with me if you would like to:

X (Twitter): https://twitter.com/mudit__01
Github: https://github.com/muditchoudhary
Linkedin: https://www.linkedin.com/in/mudit-choudhary-a87243228/