React and FastAPI Login System

By Rasyue | On December 13, 2021

React FastAPI Login Introduction

In this tutorial, we will be creating a login system with React and FastAPI Python.

FastAPI is a Python framework. It is a high performance framework that you can use to quickly setup your backend application.

On the other hand, React is a JavaScript framework developed by Facebook.

Also, if you are the type that learn better from watching videos, try this React and FastAPI Login

Now, let’s get to it.

React and FastAPI Python – Building React Application (Frontend)

Let’s setup a fresh application of React. I will be using JavaScript for this tutorial. You may opt out for TypeScript if you like.

Open your command prompt and run below commands.


npx create-react-app my-rasyue-app
// once the script runs sucessfully, run below.
cd my-rasyue-app
npm start

Now, open your preferred IDE and open the my-rasyue-app folder.

Configuring Our React Application (Frontend)

On a high level, our React application should:

  1. Have a login page and a profile page (protected page that is only accessible after logging in)
  2. Have a logout button that will clear out the JWT that is stored in localStorage
  3. The login page will have a login form with two inputs for username and email.
  4. On login form submit, we will use axios to send a POST request to the backend(FastAPI Python)

With that out of the way, let’s get cracking!

Creating Login Page

Run below command to install react-router-dom and axios

npm install react-router-dom@6
npm install axios

Open your index.js and paste the followings.

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

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  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();

We wrap the App with <BrowserRouter> to allow the usage of Routes in the application.

Now, open your App.js and paste the followings.

import './App.css';
import {
  Route,
  Routes,
} from "react-router-dom";

import Login from './Login.js'
import Profile from './Profile.js'


function App() {

  return (
    <div className="App">
      <Routes>
        <Route path="/" element={<Login />} />
        <Route
          path="/profile"
          element={<Profile />}
        />
      </Routes>
    </div>
  );
}


export default App;

We now have to create two new files Login.js and Profile.js

Go ahead and create those two files.

Inside the Login.js, paste the followings.

export default function Login(){

    return(
        <>
        
            <div style = {{minHeight: 800, marginTop: 20 }}>
                <h1>Login Page</h1>
            </div>
        
        </>
    )
}

Inside Profile.js, paste the followings.


export default function Profile(){

    return(
        <>
        
            <div style = {{minHeight: 800, marginTop: 20 }}>
                <h1>Profile Page</h1>
            </div>
            
        </>
    )
}

Open you browser and open localhost:3000

You should have something like this.

react fastapi login
React Login Page

So far, we have created 2 new pages, Profile and Login. We have also define the Routes in our App.js file.

Nothing too fancy.

Setting Up Authentication And Making Protected Page

It’s time to set up our Authentication for React.

Create a new file Auth.js and paste the followings

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



export const setToken = (token) =>{

    // set token in localStorage
    localStorage.setItem('rasyueToken', token)

}

export const fetchToken = (token) =>{

    // fetch the token
    return localStorage.getItem('rasyueToken')

}




export function RequireToken({children}) {

    
    let auth = fetchToken()
    let location = useLocation();
  
    if (!auth) {
      
      return <Navigate to="/" state={{ from: location }} />;
    }
  
    return children;
}
  

Open App.js and replace with the followings.

import './App.css';
import {
  Route,
  Routes,
} from "react-router-dom";

import Login from './Login.js'
import Profile from './Profile.js'

import {RequireToken} from './Auth.js'

function App() {

  return (
    <div className="App">
      <Routes>
        <Route path="/" element={<Login />} />
        <Route
          path="/profile"
          element={
            <RequireToken>
              <Profile />
            </RequireToken>
          }
        />
      </Routes>
    
    </div>
  );
}


export default App;

To explain what we did, we first created a new file Auth.js and inside it we define 3 functions namely, setToken, fetchToken and RequireToken

The setToken and fetchToken are to set and fetch the item we stored in localStorage.

If you are not familiar with localStorage, I suggest you read them here

The RequireToken is used in the Route in App.js. The function will receive the children path and determine if user is allowed to access the path or not.

This is the step to make a page protected, in this case we are making Profile page protected.

If a token is not available, the user would not be able to access the token.

Let’s finish up the final part of our React application for login.

React FastAPI – Completing the Login Form

Open your Login.js and paste the followings.

import {useState} from 'react'
import {setToken, fetchToken} from './Auth.js'
import {useNavigate} from "react-router-dom";
const axios = require('axios');

export default function Login(){

    const navigate = useNavigate();
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');

    const login = () =>{

        if(username === '' && password === ''){

            return

        }else{

            console.log('axios')
            axios.post('http://localhost:8000/login', {
                username: username,
                password: password
            })
            .then(function (response) {

                if(response.data.token){
                    
                    setToken(response.data.token)
                    navigate("/profile");
                }
            })
            .catch(function (error) {

                console.log(error, 'error');

            });

           
           

        }
       
    }

    return(
        <>
           
            <div style = {{minHeight: 800, marginTop: 20 }}>
                <h1>Home Page</h1>

                <div style = {{marginTop: 50 }} >
                    {
                        fetchToken() 
                        ? (
                            <p>You are logged in!</p>
                        ) 
                        : (
                            <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>
            
        </>
    )
}

Refresh and your page will look something like this.

Login Home Page

And lastly, open your Profile.js and replace with the followings.


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



export default function Profile(){

    const navigate = useNavigate();

    const signOut = () => {

        localStorage.removeItem('rasyueToken')
        navigate("/");
    }


    return(
        <>
        
            <div style = {{minHeight: 800, marginTop: 20 }}>
                <h1>Profile Page</h1>

                <p>Hi, this is your profile</p>

                <div>
                    <button type = 'button' onClick= {signOut}>Sign Out</button>
                </div>
            </div>
            
        </>
    )
}

If you test your login system right now then it won’t work just yet, we still have to create our backend.

Let’s build our FastAPI backend application.

React and FastAPI Python – Building FastAPI Application (Backend)

Let’s set up our FastAPI application.

First, make sure you have Python installed on your computer.

I will be using Anaconda and Pycharm in this tutorial because it gives more control over Python modules but you don’t have to download both Anaconda and Pycharm.

Just installing Python and using any other IDE should still work.

Create a new folder and name it anything you like and inside it create a new name main.py

Before we can use FastAPI, we need to install it first through pip. Run below command to install it.

pip install fastapi
pip install "uvicorn[standard]"
pip install pyjwt

React FastAPI Login – Building the First Hello World Page

Now, in your main.py, paste the followings.

from fastapi import FastAPI


app = FastAPI()


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

Run your FastAPI application with uvicorn main:app --reload

You should have something like this.

react fastapi login - hello world
Hello, World!

The next step is to define an endpoint that will handle a login request from the front-end application React.

The endpoint should also generate a JWT token and communicate with MongoDB database.

React FastAPI Login – Creating Login Endpoint

Open up your main.py and paste the followings.

from fastapi import FastAPI
from typing import Optional
from pydantic import BaseModel

app = FastAPI()


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


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


@app.post("/login")
async def login_user(login_item: LoginItem):
    return login_item

As you can see above, we added another endpoint /login which only accepts post request that comes along with an object input login_item.

The type LoginItem was defined to make sure that post request input is solely only consists of email and password.

If we were to test the endpoint using Postman, we will get something like this.

react fastapi login postman

React FastAPI Login – Modifying Login Endpoint to Generate JWT

Now that we have the login endpoint working, the next step is to implement function to generate the JWT.

Open your main.py and replace with the followings.

from fastapi import FastAPI

import jwt
from pydantic import BaseModel
from fastapi.encoders import jsonable_encoder


SECRET_KEY = "my_secret_key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 800

dummy_user = {
    "username": "rasyue",
    "password": "rasyuepassword",
}

app = FastAPI()


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


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


@app.post("/login")
async def login_user(login_item: LoginItem):

    data = jsonable_encoder(login_item)
    if dummy_user['username'] == data['username'] and dummy_user['username'] == data['username']:
        encoded_jwt = jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM)
        return {'token': encoded_jwt }
    else:
        return {'message': 'Login failed'}




To explain the above, first, we have added JWT module to the mix as well as the jsonable_encoder.

Next, we define the SECRET_KEY, ALGORITHM and ACCESS_TOKEN_EXPIRE_MINUTES which we will use later when we want to generate our token.

We then define dummy_user which is an object that stores our credentials. Notice that I have change the email in LoginItem class to username

In a real application, we should be using the data that comes from database to when user is logging in but to make things simple, using a hard-coded credentials is fine.

Go ahead and test out your endpoint with Postman.

react fastapi login postman
login failed with Postman

That’s it for our backend.

Testing Our Login Form

Finally, everything is set, let’s test out our login system.

Profile Page

The Profile page is protected, without the token, you will not be able to access it. Try signing out and see what happens to the token.

The End

That’s it for this tutorial.

If you are interested to learn more about similar tutorial, checkout this tutorial that I’ve written which you can follow easily, Creating Login System in Angular and FastAPI

One comment on “React and FastAPI Login System

Leave a Reply

Your email address will not be published.

*

*
*