React Authentication - Protecting and Accessing Routes/Endpoints
Tags: react, authentication, protected, route
Published: 2021-02-05 17:37:26

In the [previous tutorial](https://dev.to/ebereplenty/react-authentication-login-h3i), we were able to successfully login our user. That was awesome.

## Jump To
* [Creating the Routes](#1)
* [Protecting Routes](#4)
* [Making API calls using ``useEffect`` Hook](#8)
* [Logout](#11)
* [Conclusion](#12)

We know that the main reason for logging in or authenticating a user is to give access to certain restricted features of an application. In view of that, this article will now focus on how to protect routes and how to access such routes. Let's begin by creating two routes. Follow my lead...

![Follow Me](https://media.giphy.com/media/3o7TKqDFaqUS5cdTgc/giphy.gif)

<a name="1"></a>
## Creating the Routes

#### Jump To
* [Create Two (2) Components](#2)
* [Set up the route](#3)

<a name="2"></a>
### Create Two (2) Components
* Create a new file in the ``src`` directory and name it ``FreeComponent.js``
* The file should have the following content:

```javascript

import React from "react";

export default function FreeComponent() {
  return (
    <div>
      <h1 className="text-center">Free Component</h1>
    </div>
  );
}

```
* Next, create a another file and name it ``AuthComponent.js``

* The file should have the following content:

```javascript

import React from "react";

export default function AuthComponent() {
  return (
    <div>
      <h1 className="text-center">Auth Component</h1>
    </div>
  );
}

```

<a name="3"></a>
### Set up the route
* Install ``react-router-dom``

```javascript

npm install --save react-router-dom

```
* Navigate to ``index.js`` file

* Import import ``BrowserRouter``

```javascript

import { BrowserRouter } from "react-router-dom";

```

* wrap the ``<App>`` component with the ``</BrowserRouter>`` component. So ``index.js`` file now looks like:

```javascript

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import "bootstrap/dist/css/bootstrap.min.css";
import { BrowserRouter } from "react-router-dom";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

```

* Now navigate to the ``App.js`` file
* Import import ``Switch`` and ``Route`` at the top of the file

```javascript

import { Switch, Route } from "react-router-dom";

```

* Replace the ``Account`` Component with the following code

```javascript

     <Switch>
        <Route exact path="/" component={Account} />
        <Route exact path="/free" component={FreeComponent} />
        <Route exact path="/auth" component={AuthComponent} />
      </Switch>

```
*You will notice that nothing changed. This is so because the Account component is still our default component when routing. However, we now have access to multiple routes*

* Add links for navigation purpose under the ``React Authentication Tutorial`` heading like so:

```javascript

     <Row>
        <Col className="text-center">
          <h1>React Authentication Tutorial</h1>

          <section id="navigation">
            <a href="/">Home</a>
            <a href="/free">Free Component</a>
            <a href="/auth">Auth Component</a>
          </section>
        </Col>
      </Row>

```
* Navigate to ``index.css`` to add the following styling for aesthetics purpose

```css

#navigation{
  margin-top: 5%;
  margin-bottom: 5%;
}

#navigation a{
  margin-right: 10%;
}

#navigation a:last-child{
  margin-right: 0;
}

```

<a name="4"></a>
## Protecting Routes

#### Jump To:
* [Get the token](#5)
* [Create a Component to Protect Routes](#6)
* [Using the ``ProtectedRoutes`` component](#7)

Having successfully setup routes, we now want to protect one (i.e. the ``AuthComponent``). To do this, we need to create a new component which will help us check if a certain condition has been met before giving allowing a user to access that route.

The condition we will be using in our own case is the token generated during our ``login``. So before we create this ``ProtectedRoute`` Component, let's go get the token from the ``Login`` component and make it available in all our application.

<a name="5"></a>
### Get the token
* Install ``universal-cookie``. This is a cookie package that helps us share a value or variable across our application

```javascript

npm i universal-cookie -s

```
* Navigate to the ``Login.js`` file

* Import ``universal-cookie`` at the top and initialize it like so:

```javascript

import Cookies from "universal-cookie";
const cookies = new Cookies();

```
* Next add the following code in the ``then`` block of our axios call

```javascript

       // set the cookie
        cookies.set("TOKEN", result.data.token, {
          path: "/",
        });

```
**In the code above, we are setting cookie with ``cookie.set()``. It takes 3 arguments: ``Name`` of the cookie (``"TOKEN"``. it can be any name; just keep it in mind), ``Value`` of the cookie (``result.data.token``) and which page or route we want it to be available (setting the ``path`` to ``"/"`` makes the cookie available in all the pages). Hopefully, that makes sense**

* Below the cookie.set(), add the following line of code to redirect the user to the authComponent after a successful login

```javascript

        // redirect user to the auth page
        window.location.href = "/auth";

```
*If you checkout the Login, it should redirect you to the auth page*

<a name="6"></a>
### Create a Component to Protect Routes
Since we have made the token available across the whole application, we now have access to it on all the components or pages already created or yet to be created. Let's continue...

* Create a file with a the name: ``ProtectedRoutes.js``

* Enter the following code into the file

```javascript

import React from "react";
import { Route, Redirect } from "react-router-dom";
import Cookies from "universal-cookie";
const cookies = new Cookies();

// receives component and any other props represented by ...rest
export default function ProtectedRoutes({ component: Component, ...rest }) {
  return (

    // this route takes other route assigned to it from the App.js and return the same route if condition is met
    <Route
      {...rest}
      render={(props) => {
        // get cookie from browser if logged in
        const token = cookies.get("TOKEN");

        // return route if there is a valid token set in the cookie
        if (token) {
          return <Component {...props} />;
        } else {
          // return the user to the landing page if there is no valid token set
          return (
            <Redirect
              to={{
                pathname: "/",
                state: {
                  // sets the location a user was about to assess before being redirected to login
                  from: props.location,
                },
              }}
            />
          );
        }
      }}
    />
  );
}

```
> Hold up! Hold up!! What is actually going on in the ``ProtectedRoutes`` component?

*First of all, this is more like a template. What actually changes is the condition on which our ``ProtectedRoutes`` component is based. In our own case, it is based on the ``token`` received from the cookie upon login. So in other application, the condition may be different*

**Now, this is what is going on here. The ``ProtectedRoutes`` component receives a ``component`` and then decides if the component should be returned to the user or not. In order to take this decision, it checks if there is a valid ``token`` (token is set upon a successful login) coming from the cookie. If the token is ``undefined``, then it redirects to the default ``path`` (the landing page in our own case).**

*The comments in the code will also guide you to understanding what is going on in the component. Follow Patiently...*

<a name="7"></a>
### Using the ``ProtectedRoutes`` component
Let's now use the ``ProtectedRoutes`` component to guard our Auth Component since we want it to be accessible only to authenticated users.

* Navigate to the ``App.js`` file

* Import the ``ProtectedRoutes`` component 

```javascript

import ProtectedRoutes from "./ProtectedRoutes";

```
* Replace ``<Route exact path="/auth" component={AuthComponent} />`` with ``<ProtectedRoutes path="/auth" component={AuthComponent} />``

> My ``App.js`` at this point looks like this:

```javascript

import { Switch, Route } from "react-router-dom";
import { Container, Col, Row } from "react-bootstrap";
import Account from "./Account";
import FreeComponent from "./FreeComponent";
import AuthComponent from "./AuthComponent";
import ProtectedRoutes from "./ProtectedRoutes";

function App() {
  return (
    <Container>
      <Row>
        <Col className="text-center">
          <h1>React Authentication Tutorial</h1>

          <section id="navigation">
            <a href="/">Home</a>
            <a href="/free">Free Component</a>
            <a href="/auth">Auth Component</a>
          </section>
        </Col>
      </Row>

      {/* create routes here */}
      <Switch>
        <Route exact path="/" component={Account} />
        <Route exact path="/free" component={FreeComponent} />
        <ProtectedRoutes path="/auth" component={AuthComponent} />
      </Switch>
    </Container>
  );
}

export default App;

```

> Now try to access ``http://localhost:3000/auth`` without logging in and notice how it redirects you to the landing page. That is amazing. Right?

See Mine Below

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7wmf5t65c946kqsndg8f.gif)

<a name-"8"></a>
## Making API calls using ``useEffect`` Hook

#### Jump To:
* [API call to a free endpoint](#9)
* [API call to a protected endpoint](#10)

We have already seen how to make API calls using Axios when we created our [Register](https://dev.to/ebereplenty/react-authentication-part-1-39aj) and [Login](https://dev.to/ebereplenty/react-authentication-login-h3i). I want to use this section to clearly different how to make API call to different kinds of endpoints. 

We will make API call to two endpoints that we created in [this tutorial](https://dev.to/ebereplenty/authentication-with-nodejs-and-mongodb-part-4-4p37) using the ``useEffect`` hook. The ``useEffect`` hook does for react ``functional component`` what ``componentDidMount()`` does for react ``class component``.

1. **Free Endpoint:** ``https://nodejs-mongodb-auth-app.herokuapp.com/free-endpoint``

2. **Protected Endpoint:** ``https://nodejs-mongodb-auth-app.herokuapp.com/auth-endpoint``

<a name-"9"></a>
### API call to a free endpoint
* Navigate to the ``FreeComponent.js`` file
* Import ``useEffect`` and ``useState`` by Adjusting your ``react`` import line with the following

```javascript

import React, { useEffect, useState,  } from "react";

```
* Next, import axios

```javascript

import axios from "axios";

```
* Set an initial state for ``message`` like so:

```javascript

const [message, setMessage] = useState("");

```

* Just above the ``return`` statement, declare the ``useEffect`` function like so

```javascript

  useEffect(() => {

  }, [])

```
*The empty array (i.e. ``[]``) is very important to avoid continuous execution after the API call have been completed*

* In the function, set the following configurations

```javascript

  useEffect(() => {
    // set configurations for the API call here
    const configuration = {
      method: "get",
      url: "https://nodejs-mongodb-auth-app.herokuapp.com/free-endpoint",
    };
  }, [])

```
* Next make the API call using axios like so:

```javascript

  // useEffect automatically executes once the page is fully loaded
  useEffect(() => {
    // set configurations for the API call here
    const configuration = {
      method: "get",
      url: "https://nodejs-mongodb-auth-app.herokuapp.com/free-endpoint",
    };

    // make the API call
    axios(configuration)
      .then((result) => {
        // assign the message in our result to the message we initialized above
        setMessage(result.data.message);
      })
      .catch((error) => {
        error = new Error();
      });
  }, [])

```

**``setMessage(result.data.message);`` assigns the message in our result(i.e. result.data.message) to the message we initialized above. Now we can display the ``message`` in our component**

*I have already shown in the [last article](https://dev.to/ebereplenty/react-authentication-login-h3i) how to check for the result of our API call in the console. You can do that to trace how we got to ``result.data.message``.*

* To display the ``message`` we got on our ``FreeComponent`` page, enter the following code below ``<h1 className="text-center">Free Component</h1>`` line

```javascript

<h3 className="text-center text-danger">{message}</h3>

```
*React will read the ``message`` as a variable because of the curly bracket. If the ``message`` is without the curly bracket, React reads is as a normal text*

> This is my ``FreeComponent.js`` file at this point:

```javascript

import React, { useEffect, useState } from "react";
import axios from "axios";

export default function FreeComponent() {
  // set an initial state for the message we will receive after the API call
  const [message, setMessage] = useState("");

  // useEffect automatically executes once the page is fully loaded
  useEffect(() => {
    // set configurations for the API call here
    const configuration = {
      method: "get",
      url: "https://nodejs-mongodb-auth-app.herokuapp.com/free-endpoint",
    };

    // make the API call
    axios(configuration)
      .then((result) => {
        // assign the message in our result to the message we initialized above
        setMessage(result.data.message);
      })
      .catch((error) => {
        error = new Error();
      });
  }, []);

  return (
    <div>
      <h1 className="text-center">Free Component</h1>

      {/* displaying our message from our API call */}
      <h3 className="text-center text-danger">{message}</h3>
    </div>
  );
}

```
* My ``FreeComponent`` Page right now:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7ap2bd2okfjwsrzl9a67.JPG)

<a name-"10"></a>
### API call to a protected endpoint
* Navigate to the ``AuthComponent.js`` file
* Import ``useEffect`` and ``useState`` by Adjusting your ``react`` import line with the following

```javascript

import React, { useEffect, useState,  } from "react";

```
* Next, import axios

```javascript

import axios from "axios";

```
* Import and initialize universal-cookie like so:

```javascript

import Cookies from "universal-cookie";
const cookies = new Cookies();

```

* Get the token generated on login like so:

```javascript

const token = cookies.get("TOKEN");

```

* Set an initial state for ``message`` like so:

```javascript

const [message, setMessage] = useState("");

```

* Just above the ``return`` statement, declare the ``useEffect`` function like so

```javascript

  useEffect(() => {

  }, [])

```
*The empty array (i.e. ``[]``) is very important to avoid continuous execution after the API call have been completed*

* In the function, set the following configurations

```javascript

  useEffect(() => {
    // set configurations for the API call here
    const configuration = {
      method: "get",
      url: "https://nodejs-mongodb-auth-app.herokuapp.com/auth-endpoint",
      headers: {
        Authorization: `Bearer ${token}`,
      },
    };
  }, [])

```
**Notice that this configuration contains a ``header``. That is the main difference from the ``free-endpoint`` configuration. This is so because the ``auth-enpoint`` is a protected endpoint that is only accessible using an ``Authorization token`` as specified in this [article](https://dev.to/ebereplenty/authentication-with-nodejs-and-mongodb-part-4-4p37). So it is in the header that we specify the ``Authorization token``. Without this header, the API call will return a ``403:Forbidden`` error**

* Next, we make the API call like so

```javascript

// useEffect automatically executes once the page is fully loaded
  useEffect(() => {
    // set configurations for the API call here
    const configuration = {
      method: "get",
      url: "https://nodejs-mongodb-auth-app.herokuapp.com/auth-endpoint",
      headers: {
        Authorization: `Bearer ${token}`,
      },
    };

    // make the API call
    axios(configuration)
      .then((result) => {
        // assign the message in our result to the message we initialized above
        setMessage(result.data.message);
      })
      .catch((error) => {
        error = new Error();
      });
  }, []);

```

* To display the ``message`` we got on our ``AuthComponent`` page, enter the following code below ``<h1 className="text-center">Auth Component</h1>`` line

```javascript

<h3 className="text-center text-danger">{message}</h3>

```

* My ``AuthComponent`` Page right now:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qqud8uirnrepmfxd0mff.JPG)

<a name="11"></a>
## Logout Function
Finally, we need to logout when we are done viewing our ``authComponent`` Page. You know for security reasons. To do this, add a button in the ``authComponent`` page. 

* Import the Button component like so:

```javascript

import { Button } from "react-bootstrap";

```
* Add the following code below the texts

```javascript

<Button type="submit" variant="danger">Logout</Button>

```

* We want a logout function to be triggered when the button is clicked so add ``onClick={() => logout()}`` to the button options. So our button will look like this:

```javascript

{/* logout */}
<Button type="submit" variant="danger" onClick={() => logout()}>
   Logout
</Button>

```

* Now lets create the function. Enter the following code just above the return

```javascript

  // logout
  const logout = () => {
    
  }

```

* Add the following code to the logout function to remove or destroy the token generated during login


```javascript

// logout
  const logout = () => {
    // destroy the cookie
    cookies.remove("TOKEN", { path: "/" });
  }

```

* Redirect the user to the landing page with the following code

```javascript

// logout
  const logout = () => {
    // destroy the cookie
    cookies.remove("TOKEN", { path: "/" });
    // redirect user to the landing page
    window.location.href = "/";
  }

```
* Add ``className="text-center"`` to the parent ``div`` of the ``AuthComponent``. Just to centralize the whole page. You can now remove it from other places. My ``AuthComponent.js`` file now has the following content:

```javascript

import React, { useEffect, useState } from "react";
import { Button } from "react-bootstrap";
import axios from "axios";
import Cookies from "universal-cookie";
const cookies = new Cookies();

// get token generated on login
const token = cookies.get("TOKEN");

export default function AuthComponent() {
  // set an initial state for the message we will receive after the API call
  const [message, setMessage] = useState("");

  // useEffect automatically executes once the page is fully loaded
  useEffect(() => {
    // set configurations for the API call here
    const configuration = {
      method: "get",
      url: "https://nodejs-mongodb-auth-app.herokuapp.com/auth-endpoint",
      headers: {
        Authorization: `Bearer ${token}`,
      },
    };

    // make the API call
    axios(configuration)
      .then((result) => {
        // assign the message in our result to the message we initialized above
        setMessage(result.data.message);
      })
      .catch((error) => {
        error = new Error();
      });
  }, []);

  // logout
  const logout = () => {
    // destroy the cookie
    cookies.remove("TOKEN", { path: "/" });
    // redirect user to the landing page
    window.location.href = "/";
  }

  return (
    <div className="text-center">
      <h1>Auth Component</h1>

      {/* displaying our message from our API call */}
      <h3 className="text-danger">{message}</h3>

      {/* logout */}
      <Button type="submit" variant="danger" onClick={() => logout()}>
        Logout
      </Button>
    </div>
  );
}

```

> My working Application is demonstrated below

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8b4g8m53ckqc7ns0tdo8.gif)

And that is it for React Authentication!!!

Congratulations! You are now a React Authentication Pro!!!

![Celebrating Small Wins](https://media.giphy.com/media/mp1JYId8n0t3y/giphy.gif)

<a name="12"></a>
## Conclusion
We began this series from how to [Register](https://dev.to/ebereplenty/react-authentication-part-1-39aj) a user. We then discussed how to [Login](https://dev.to/ebereplenty/react-authentication-login-h3i) such a user in the last article. In this article, we have been able to see how to protect route(s) and access them. We have also been able to see how to make API calls depending on the type of endpoint (free or protected). We then concluded by learning how to logout if we are logged in. 

That was a lot. No doubt. However, it helped us cover a lot of topics such as hooks, cookie, axios etc. So YES! it was worth it.

All codes are [here](https://github.com/EBEREGIT/react-auth/tree/protected-routes)

Please share to help someone. Thank you for reading

I promise more content coming your way soon