Truly Protected React Routes
Tags: react, security
Published: 2021-01-26 14:02:15

---
title : "Truly Protected React Routes"
description: "Secure authentication in React"
canonical_url: "https://www.daggala.com/truly-protected-react-routes/"
published: true
---

Are you in doubt that your React routes are really protected ? There are lots of tutorials out there that talk about “secured routes”, “protected routes”, “private routes” or “restricted routes”. It’s pretty misleading because even though you have protected routes, **it is possible** to get past your login page and get access to all the code in your protected routes.

Perhaps people are telling you that it isn’t worth going for server side rendering (SSR) in order to truly protect the graphic content of your website. Maybe they’re saying that securing the backend should be enough because that will prevent you from displaying any sensitive data to fake-logged-in users. But **WHAT IF** you still want more security and you want to block all access? After all, you don’t want your competitors to hack into your admin dashboard, to see how you’re progressing or stealing your ideas.

This article will answer the following questions

 - [what's not secure about protecting routes in the client?](#secure)
 - [why do we protect routes in the client?](#why)
 - [in which case do I want to have truly protected routes?](#when)
 - [how to truly protect routes](#protected)


<h2 id="secure">What's not secure about protecting routes in the client?</h2>

In React there is nothing such as truly private routes as it's a single page application (SPA) which means that all the code is served to the browser.

This is typically how we protect routes in the browser:

```jsx
{isLoggedIn ? <PrivateRoutes> : <PublicRoutes/>}
```

With this code here above, you can't guarantee that the user won't tweak your javascript, change `isLoggedIn` to value true and pretend to be an authenticated user.

Let's see how we can get access to ALL the code of your application. Here's a [sandbox example](https://codesandbox.io/s/hacking-past-react-login-page-t4hzj?file=/src/App.js) where I've made a typical login system with protected routes. Notice that I lazy loaded two components: "PrivatePage" and the "LoginPage". Then I used the "classic" way of importing "AnotherPrivatePage" even though that component is not being used (this is on purpose).

```javascript
import React, { useState, Suspense } from "react"
import AnotherPrivatePage from "./AnotherPrivatePage"
const PrivatePage = React.lazy(() => import("./PrivatePage"))
const LoginPage = React.lazy(() => import("./LoginPage"))

export default function App() {
  const [isAuthenticated, setAuthenticated] = useState(false)
  return (
    <Suspense fallback={<div>Loading .. </div>}>
      {isAuthenticated ? <PrivatePage /> : <LoginPage />}
    </Suspense>
  )
}
```

You can either follow the article or test yourself by opening up the sandbox example, and opening page in new window by clicking on the two squares in the upper right corner (the icon can vary between browsers):

![codesandbox](https://www.daggala.com/static/7f28fdcbf8b0a686cafd119239f7094d/fc2a6/screenshot_codesandbox.png)

Go to devtools by right clicking, choose "Inspect" (if you're in Chrome). Then go to "Sources".

![source_chrome](https://www.daggala.com/static/d332e1fcb9cc600109662e184a1397e0/47218/source_chrome.png)

Here above you can see that we have two components loaded to the browser, "LoginPage" because isAuthenticated = false. We also have "AnotherPrivatePage" because if you don't lazy load, we can very easily access that component as well. The "hacker" doesn't even have to hack to look around and read the code and maybe see some static data.

It needs a bit more effort to get hold of the other component "PrivatePage.js" as it's lazy loaded. There are lots of ways to do that, but here's one:
Install React dev tools if you don't have it already, go to ⚛️Components:

![devtools1](https://www.daggala.com/static/04d0a228ac045b4e133ee99cbc574f2f/fcda8/devtools1.png)

Then click on "App" and change hook's state to true:

![devtools2](https://www.daggala.com/static/0baf76bf063776cf34280137ec575050/fcda8/devtools2.png)

And you'll see how we get access to the "PrivatePage", the last component we didn't have loaded in of our application and was supposed to be protected. There are of course lots of other ways to hack React. To increase security you could for example disable access to devtools in production but there's most often some other way to get around things.

<h2 id="why">But why do we then protect our routes in the front end?</h2>

You can protect your components/graphics on a:

- component level

- route level

Either way, the main reason for why we're protecting those graphics is just to make the user experience nicer. The reason why we do it on a route level is just to make our code more organized by avoiding duplications.

How are protected routes nicer for the user ? Imagine, the user has already visited our page. Next time he visits, he'll tap the url of your website and his browser autocompletes the website url without adding /login to the end of the URL. He goes straight to http://www.somewebsite.com, but he's not authenticated anymore (let's say that he logged out the last time or his authorization token has expired). And because he's not logged in anymore the user will see the page without any content and no possibility to interact with anything that has to do with server data. It would be nicer for the user to have no direct access to the private pages and instead automatically land on the login page.

<h2 id="when">But is it so important to have truly protected routes?</h2>

In the worst case scenario, the user can hack its way with javscript to your private routes and will see some empty tables, graphs, or messages that tell you that there is no data etc. And without content, your website will look like nothing, might even be ugly or at least it will be unusable. Well that's not so serious, we could even say that our hacker deserves that! 😈. But you have to make sure that there is no possibility for the hacker to access sensitive data 🔓 You should not leave any sensitive static data in your client and ensure that all your API endpoints are secure and make the server throw 401 if the user is not really authenticated and authorized.

But is that really enough? Like I said above you might have built an admin dashboard for your company. Even without access to sensitive data, your competitor could possibly deduce where your company is heading by reading any static texts in your app, or by trying to make sense of your graphics, even though they're missing the content. Apart from that, truly securing the private part of your app adds an extra layer of security to your app, which can only be positive.

![gandalf](https://www.daggala.com/static/e1e5545adcbdbd635e7dd96b90f755e5/1c72d/gandalf.jpg)

<h2 id="protected">How to make truly secured routes?</h3>

There are several ways to achieve this. You could use SSR to solve this problem or you could stay with 100% SPA and serve your application in two parts. I've an example of the how to achieve the latter solution. There are lots of ways to do this and here I have an example of this using Express server in Node.js that serves two different SPAs, one containing the login page and the other containing the app itself. You can see this project <a href="https://github.com/daggala/secured-routes">here on github</a>.

If you clone that project and run it, you should be aware that it takes pretty much time. Instead you can also just follow the article and check out the code.

If you run the project and go to devtools, you'll see in "sources" that you only have the login page loaded to the browser.

![unauthenticated](https://www.daggala.com/static/3abc06b3ca12f34a548220de040c717c/fcda8/unauthenticated.png)

Here there's no possibility to access the authenticated part of the application because it won't be served to the browser **unless** you provide the correct auth inputs in username and password thanks to this code in server.js

```javascript
app.get("/protected", (req, res) => {
  if (req.signedCookies.name === "admin") {
    app.use(express.static(path.join(__dirname, `/${privatePage}/build`)))
    res.sendFile(path.join(__dirname, `/${privatePage}/build/index.html`))
  }
})
```

You can try to log in, username: `admin` and password: `123`...

and voilà:

![authenticated](https://www.daggala.com/static/014c6e05e4f53841532255d3f1e47b64/fcda8/authenticated.png)

Here we're logged in and now we have the authenticated part of the application loaded in the browser and as a side effect, the login page is no more loaded in the browser.

I hope this article has been useful for boosting the security of some of your websites that might use some extra layer of restriction! If you found this article helpful, don't hesitate to leave a comment or share it with others. Same of course if you have something that you would like to point out :) 

<a href="https://www.daggala.com/">This post was originally publisehd on daggala.com</a>, November 16, 2020