Login Authentication With React And FastAPI
Tags: javascript, python, webdev, react
Published: 2021-12-24 20:17:00

### Introduction

In this tutorial, we'll be building a login authentication using React and FastApi. This will help show how we can use both packages for a login authentication process but before that, let's take at React and also what FastApi is.

### What is FastApi

FastAPI is a modern, fast (high-performance) web framework for building APIs with Python. It supports both synchronous and asynchronous actions, data validation, authentication, and interactive API documentation, all of which are powered by OpenAPI. It comes with exciting features like:

### What is React

React is a user interface development library. It can construct full-stack apps by talking with a server/API and operates as a SPA (single page app) on the client. Because it is competent and directly equivalent to frameworks like Angular or Vue, React is frequently referred to as a frontend "framework".

### Requirements

- Python installed.
- Basic knowledge of Javascript.
- Basic Knowledge of React.
- Knowledge on python is a plus.

#### Installing FastAPI

open up our terminal and cd into our `project folder` and write the following:

```bash
mkdir backend
```

`cd` into the just created folder and run the following:

```bash
pip install fastapi
```
```bash
pip install "uvicorn[standard]"
```

```bash
pip install pyjwt
```

let's leave that for later and proceed with building our frontend.

#### Building The Frontend

let's create and app and install the following packages:

```bash
npx create-react-app frontend
```

Next we install the following packages:

```bash
npm install axios react-router-dom
```

After we've done that, navigate to `src/index.js` and import `BrowserRouter` :

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

We then have to replace the `React.StrictMode` tags with this:

```javascript
<BrowserRouter>
    <App />
  </BrowserRouter>,
```

Now head over to `app.js` and import this:

```javascript
import { Routes, Route } from "react-router-dom";
import Login from "./login";
import Profile from "./Profile";
```

Inside our `return()` lets delete our div and replace it with this:

```javascript
  <div className ="App">
    <Routes><!---what are routes in react-!>
      <Route path="/" element = {<Login/>}/>
      <Route path="/profile" element = {<Profile/>}/>
    </Routes>
    </div>
```

Here we are using the routes to the pages we'll be creating shortly. Next let's create a file called `Login.js` in our `src` folder and paste this:

```javascript
export default function Login() {
  return (
    <>
      <h1>login page</h1>
    </>
  );
}
```

We'll also create another file called `Profile.js` and paste this:

```javascript
export default function Profile() {
  return (
    <>
      <h1>profile page</h1>
    </>
  );
}
```

Now let's start our application:

```bash
npm start
```

![login](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1b2a3tlgmltrfge0schq.PNG)

![profile](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/33c6aeisc0u5788rsugn.PNG)

As you can see, our page is working fine (also check the profile page by adding `/profile` to the url). Now that we're done with basics, let's proceed to setting up our authentication.

Let's create a new file in our `src` folder called `Auth.js` and paste this:

```javascript
import { useLocation,Navigate } from "react-router-dom"

export const setToken = (token)=>{

    localStorage.setItem('temitope', token)// make up your own token
}

export const fetchToken = (token)=>{

    return localStorage.getItem('temitope')
}

export function RequireToken({children}){

    let auth = fetchToken()
    let location = useLocation()

    if(!auth){

        return <Navigate to='/' state ={{from : location}}/>;
    }

    return children;
}
}
```

Here we created variables setting our token, fetching and also requiring our token, so let's go back to our `app.js` and import our token:

```javascript
import { RequireToken } from "./Auth";
```

We'll be adding some things in our `app.js`. In our `Route path="/profile"` let's make changes to the element by adding our `RequireToken` so our `Route path="/profile"` should look like this:

```javascript
<Route
  path="/profile"
  element={
    <RequireToken>
      <Profile />
    </RequireToken>
  }
/>
```
When we save this and go to our app, we see that our profile page is now protected and can only be accessed with a valid token. Now let's finish our login page with our login form. Head over to the login page, clear all, and paste this:

```javascript
import { useNavigate } from "react-router";
import { fetchToken } from "./Auth";

export default function Login() {
  const navigate = useNavigate();
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  //check to see if the fields are not empty
  const login = () => {
    if ((username == "") & (password == "")) {
      return;
    } else {
      // make api call to our backend. we'll leave this for later
    }
  };

  return (
    <>
      <div style={{ minHeight: 800, marginTop: 30 }}>
        <h1>login page</h1>
        <div style={{ marginTop: 30 }}>
          {fetchToken() ? (
            <p>you are logged in</p>
          ) : (
            <div>
              <form>
                <label style={{ marginRight: 10 }}>Input Username</label>
                <input
                  type="text"
                  onChange={(e) => setUsername(e.target.value)}
                />

                <label style={{ marginRight: 10 }}>Input Password</label>
                <input
                  type="text"
                  onChange={(e) => setPassword(e.target.value)}
                />

                <button onClick={login}>Login</button>
              </form>
            </div>
          )}
        </div>
      </div>
    </>
  );
}
```

We'll be pausing there for now. It's time to work on our backend.

### Creating the backend

Now lets open up our backend folder, create a `main.py` file and input the following:

```python
from fastapi import FastAPI
from pydantic import BaseModel
import jwt
from pydantic import BaseModel
from fastapi.encoders import jsonable_encoder
from fastapi.middleware.cors import CORSMiddleware


SECERT_KEY = "YOUR_FAST_API_SECRET_KEY"
ALGORITHM ="HS256"
ACCESS_TOKEN_EXPIRES_MINUTES = 800

test_user = {
   "username": "temitope",
    "password": "temipassword",

}

app = FastAPI()

origins = {
    "http://localhost",
    "http://localhost:3000",
}

app.add_middleware(
   CORSMiddleware,
    allow_origins = origins,
    allow_credentials =True,
    allow_methods = ["*"],
    allow_headers= ["*"],
)

class LoginItem(BaseModel):
    username: str
    password: str

    @app.get("/")
    def read_root():
     return {"Hello": "World"}

@app.post("/login")
async def user_login(loginitem:LoginItem):


    data = jsonable_encoder(loginitem)

    if data['username']== test_user['username'] and data['password']== test_user['password']:

        encoded_jwt = jwt.encode(data, SECERT_KEY, algorithm=ALGORITHM)
        return {"token": encoded_jwt}

    else:
        return {"message":"login failed"}
```

Here we are trying to:

- Generate a token.
- Defining a `test user object` to check against the user login credentials
- Configuring our `CORS` to allow our React app to send POST requests
- Running a check with the coming data with `test_user`.

Almost done now that we're done, let's go back to the frontend to finish things up. Head over to login.js and replace it with this:

```javascript
import { useNavigate } from "react-router";
import { fetchToken, setToken } from "./Auth";
import { useState } from "react";
import axios from "axios";

export default function Login() {
  const navigate = useNavigate();
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  //check to see if the fields are not empty
  const login = () => {
    if ((username == "") & (password == "")) {
      return;
    } else {
      // make api call to our backend. we'll leave thisfor later
      axios
        .post("http://localhost:8000/login", {
          username: username,
          password: password,
        })
        .then(function (response) {
          console.log(response.data.token, "response.data.token");
          if (response.data.token) {
            setToken(response.data.token);
            navigate("/profile");
          }
        })
        .catch(function (error) {
          console.log(error, "error");
        });
    }
  };

  return (
    <div style={{ minHeight: 800, marginTop: 30 }}>
      <h1>login page</h1>
      <div style={{ marginTop: 30 }}>
        {fetchToken() ? (
          <p>you are logged in</p>
        ) : (
          <div>
            <form>
              <label style={{ marginRight: 10 }}>Input Username</label>
              <input
                type="text"
                onChange={(e) => setUsername(e.target.value)}
              />

              <label style={{ marginRight: 10 }}>Input Password</label>
              <input
                type="text"
                onChange={(e) => setPassword(e.target.value)}
              />

              <button type="button" onClick={login}>
                Login
              </button>
            </form>
          </div>
        )}
      </div>
    </div>
  );
}
```

We'll also make changes to our `profile.js` so let's open it up and paste this:

```javascript
import { useNavigate } from "react-router";
export default function Profile() {
  const navigate = useNavigate();

  const signOut = () => {
    localStorage.removeItem("temitope");
    navigate("/");
  };

  return (
    <>
      <div style={{ marginTop: 20, minHeight: 700 }}>
        <h1>Profile page</h1>
        <p>Hello there, welcome to your profile page</p>

        <button onClick={signOut}>sign out</button>
      </div>
    </>
  );
}
```

We're done, let' test our app . Run the code:

```bash
uvicorn main:app --reload
```

![finish](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3bga185xeiqrih0bse69.gif)
### Conclusion
 In the tutorial, we looked at what FastApi is and also what React is. We also learned how to install FastApi and React using these ideas to build our login authentication. Here's a link to the repo on [github](https://github.com/oyedeletemitope/login-authentication-with-react-and-FastAPI). Happy coding!