React Protected Routes - How to Make React Router Protected Route
In this post you will learn how to protect your routes inside React Router in your React application.
Just from the start I must tell you that it is impossible to protect your routes on the client side. Anybody can access your Javascript, execute code and access your page.
This is why it is extremely important to protect your data on the backend and you don't allow person who is not logged it to access your API.
With that being cleared let's look on our application.
As you can see here I already prepared an application with 2 pages. We have here Dashboard and Protected routes. What we want to do is access this /protected
route only when our user is logged it.
Let's look what we have inside our application.
// main.js
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
Inside main.js
we wrapped everything with BrowserRouter
because we are using react-router which is the most popular solution for routing inside React.
const App = () => {
return (
<div>
<h1>Hello monsterlessons</h1>
<Link to="/">Dashboard</Link>
<Link to="/protected">Protected</Link>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route
path="/protected"
element={<Protected />}
/>
</Routes>
</div>
);
};
Inside our App
component we have 2 links and 2 routes to our Dashboard and Protected components. Inside our components we don't have anything at all but just text.
The way how we will protect our routes doesn't have anything to do with react-router. The main idea is that we can wrap our components that we want to protect with additional component which will check if we can access a component.
This is how the usage will look like.
<Route
path="/protected"
element={
<Auth>
<Protected />
</Auth>
}
/>
We just wrapped Protected
with Auth
component that we will create in a second.
Sync protection
Now let's create our Auth
component.
import { Navigate } from "react-router-dom";
const Auth = ({ children }) => {
if (localStorage.getItem("token")) {
return children;
}
return <Navigate to="/" />;
};
Here we created an example of synchronous check. We try to get a value from localStorage and if it is there we render our child component. If it is not we redirect a user to homepage.
As you can see in browser we can't access our /protected
without a token. If we add a token to localStorage with any value it will work.
Async protection
But it is not enough for real application as we typically fetch current user from the API which means our check must be asynchronous and we must wait until we have a user before we decide if we render a component.
const Auth = ({ children }) => {
const [currentUser, setCurrentUser] = useState(undefined);
useEffect(() => {
setTimeout(() => {
if (localStorage.getItem("token")) {
setCurrentUser({ id: "1", name: "foo" });
} else {
setCurrentUser(null);
}
}, 2000);
}, []);
if (currentUser === undefined) {
return null;
}
if (!currentUser) {
return <Navigate to="/" />;
}
return children;
};
Here is an example of async check. First of all we created a state for currentUser
. Secondly we try to load a user on initialize of Auth
component. In real application you would want to do an API call here but for simplicity I wrote localStorage check inside setTimeout
to simulate long API request.
If we are logged in we set an object with data to currentUser
in other case we set null
. Additionally we return null
in this component if we don't have currentUser
yet. It means that it won't render anything. If we got currentUser
information but it is null then we redirect a user to homepage. And if we are logged in we render the child component.
As you can see in browser we have a delay before we see the content of our private route. This is our timeout while we are getting a user from the API.
Now we built a reusable component which can be applied to any place.
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!
📚 Source code of what we've done