Scalable Protected Routes with React Router

How to reroute users to a public login page when they try to access protected routes.

Background

The fundamental core of react-routers functionality is made clear when you look at the <Route> component provided by the package:

import Home from './components/Home.js'<Route path="/" component={Home} />// Or this will render the same thing
<Route path="/"/> <Home /> </Route>

When the user navigates to that URL in their browser, the router will take charge and show the user the component that you want to register.

But what if you don’t want to allow the user to get to a specific page?

Protected Routes

In the React-Router package the primary tool that we have to help achieve this goal is the <Redirect>component. Rendering a <Redirect> will navigate to a new location. The new location will override the current location in the history stack, like server-side redirects (HTTP 3xx) do.

To take our previous example and expand it a bit, the <Redirect> component could be used like so:

<Route path = "/" component = {Home} /><Route path = "/admin-dashboard" component = {LoginPage} />     <Redirect to="/login"></Route>

This will tell the router that we want to redirect the user to the public login page if they try to access our private component. However this setup will redirect the user no matter whether or not they are logged in. How do we build the logic to check the login state and then render that private component if the user is logged in? The simplest way is to do something like this:

<Route exact path="/">
{loggedIn ? <Redirect to="/dashboard" /> : <PublicHomePage />}
</Route>

This demo from the react-router documentation definitely does the trick — it will block any non-authenticated users from accessing that page. The only drawback here is that if we take a larger application with more routes, then we will need to do this for every single protected route, which is not very DRY programming. The solution is scalable protected routes, using a higher order component.

Scalable protected routes

function PrivateRoute({ children, ...rest }) {
return (
<Route
{...rest}
render={({ location }) =>
fakeAuth.isAuthenticated ? (
children
) : (
<Redirect
to={{
pathname: "/login",
state: { from: location }
}}
/>
)
}
/>
);
}

This will allow you to use a component <PrivateRoute /> that will take the component that you nest inside the route and render them should the boolean fakeAuth be evaluated as true. Let’s look at each part of this code and break it down.

  1. Starting from the components inputs, we can see that the component takes the props object and destructures it using the JS syntax into 2 variables that we want to reference inside the component. If you didn’t use destructuring these variables would be passed in on the props object and accessed with props.children, props.{propName} I will explain the second value in a moment.
  2. The …rest syntax in javascript is a shorthand way to assign the remaining properties of an object into another object. Take the following example: let {a, b, …rest} = {a: 10, b: 20, c: 30, d: 40} a; // 10 b; // 20 rest; // { c: 30, d: 40 } so in the example above the …rest object will give us access to any props passed into the component by their name (if I pass a string to the component — testprop="string”then I can access that inside the component using the variable testprop)
  3. Finally, the children property is a special property in react that gives you access to the information passed inbetween the JSX tags of a component. in this case this means the component inbetween the <Route></Route> tags.

So finally, you can use the component above like so:

<Route path = "/" component = {Home} /><PrivateRoute path="/admin-dashboard">
<AdminDashboard />
</PrivateRoute>

One final point is that if you have the PrivateRoute component defined in another file, then you will need to pass the authentication status to that component as props. IE:

<PrivateRoute path="/admin-dashboard" authStatus={localAuthStatus}>
<AdminDashboard />
</PrivateRoute>

Thank you for reading, I hope that you are able to use this info in your projects!

~ Alex Zito-Wolf

Product Manager + Software Developer. Interested in Travel, Culture, and the Internet.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store