Implementing private routes with React Router and Hooks

Ceci García García
Trabe
Published in
3 min readJun 17, 2019

Recently I had to configure as private some routes of a React app (only accesible for authenticated users). This post describes the basic implementation of the app that covers:

  • Routing managed with React Router.
  • Private routes only accesible for authenticated users.
  • Auth data accesible from any component using React Context.

Initial setup

We create a simple React app with a common layout and a dynamic content that changes depending on the current route:

The <Router> component defines all the possible routes of our app and their corresponding components:

We want to configure each route as public or private (or, in a future, some more specific restrictions like “only for admin users”). There are a lot of ways to do that, but the one we chose consists in delegating the responsibility to each route. This way, a route will render the corresponding component when the user is already authenticated or the sign in page when they are not. To do that, we need our <Route> components to have access to the auth data.

Providing the auth data to the components

No matter the authentication method your app is using, most probably you will need to store the auth data of the current user somewhere in the app, and some of your components will need to read from that data (our private routes, for example).

We can encapsulate all this logic in one single component that:

  • Checks if the user is already logged in and if so, stores their auth data.
  • Provides access to the data to all its children.
  • Provides handlers to: store the auth data of a user just logged in, and remove the auth data of a user just logged out.

We’ll do so by using the React Context and the useContext Hook:

In his last post, my colleague David Barral covered how we use the React Context using the example of an auth provider. The post explains why we implement Context providers like above. Have a look at it if you haven’t already!

Remember that we have to place the <AuthDataProvider> in the component hierarchy in a higher level that the customer components that need to read from the auth data context.

As we have seen above, our <Route> components inside the <Router> will need to access the auth data. Other components within the <Layout> like a box in the top bar of the app that shows the user info and a link to do the logout, will need to access this data too. The <AuthDataProvider> should be placed higher in the hierarchy than the <Layout> and the <Router> in our app:

Now all components placed inside the <AuthDataProvider> will have access to the auth data. For example, the box that shows the user info and the link to logout:

or the sign-in form that will be rendered inside the <SignInPage>:

Defining private routes

Finally, we need to configure all our routes as private (only accesible for authenticated users) but the sign in page. To do so, we’ll implement a wrapper <PrivateRoute> for the <Route> components from React Router. The wrapper will make sure that the user is already authenticated before defining the matching component and render the sign in page if she isn’t:

Summing up

Implementing private routes is quite simple with React Router and React Context. There’re a lot of ways to do that, but I found this one specially focused and simple. I hope it helps!

--

--