Authenticate your React App with Firebase in 2023

Crafting a simple react-app and authenticating it with firebase

·

31 min read

Authenticate your React App with Firebase in 2023

Hi there, are you looking to know how to secure your react app with firebase, then this article is for you. In this article, I will show you how to authenticate your React apps using Firebase in 2023.

Outlines

  1. Requirements/Prerequisites for authentication with Firebase

  2. Vite (a better alternative to create-react-app).

  3. Setting up your React App

  4. Styling with tailwind css

  5. Why is user authentication important?

  6. What is Firebase

  7. Setting up Firebase

  8. Integrating Firebase into our App

  9. Creating a database with cloud firestore

  10. Finalizing the App authenication

Requirements

  1. NodeJS installed. if you don't have it installed, you can get it from here

  2. A code editor like Vscode

  3. A Google account to use Firebase

  4. Basic knowledge of React, React-Router-dom and useContext hook

Setting up your React App with Vite

You will be using Vite to create the React app. Vite is a faster and more lightweight alternative to Create React App. Here's how you can set up a new React app using Vite:

  1. Make sure you have Node.js installed on your system. If you don't have it installed, you can download it from the official Node.js website here and follow the installation instructions.

  2. Open your terminal or command prompt.

  3. Install Vite globally on your system using npm by typing this command in your terminal below

     npm install -g create-vite
    

4. Create a new React app using Vite:

Replace react-firebase-auth with the desired name of your application. The --template react flag tells Vite to use the React template.

create-vite auth-app --template react

5. Change the directory to the newly created app

cd auth-app

6. Install the app's dependencies: now run this command for installing your app dependencies which include react-firebase-hooks

npm install react-firebase-hooks
  1. Start the development server:
npm run dev

Vite will launch the development server, and your React app will be available at http://127.0.0.1:5173 by default.

Now, If you see this image on your screen, you have a new React app created with Vite, and you can start building your application.

Arranging the folder structure for the app

After launching the app with Vite, you do a clean-up and set up your folder structure.

Clean-up of the app

React installation normally comes with some default files that won't be needed moving forward, so removing them and starting on a clean slate is best. App.css should be deleted from the src folder. Clean up the App.js file too and make sure it looks like this:

function App() {

  return (
    <>

    </>
  )
}

export default App

After cleaning up, arrange and set up the folder structure you will use in the app.

So in the src directory, you are left with your App.js and main.jsx file, Next, install tailwind css which you will be using to style your app.

Setting up Tailwind in the App

If you want to know more about tailwind, you can click here to learn more about the documentation.

To install Tailwind CSS, follow the following steps:

  1. First, Install the required packages on your terminal.

      npm install -D tailwindcss postcss autoprefixer
    
  2. Create a configuration file for your project. To generate this default configuration, you can run:

      npx tailwindcss init -p
    

    This will create a tailwind.config.js and postcss.config.js file in your project root directory.

  3. Create a file named index.css in the src directory and add the @tailwind directives for each of Tailwind’s layers to the file:

      @tailwind base;
      @tailwind components;
      @tailwind utilities;
    
  4. Add the paths to all of your template files in your tailwind.config.js file:

      /** @type {import('tailwindcss').Config} */
      module.exports = {
       content: ["./src/**/*.{html,js,jsx}"],
       theme: {
         extend: {},
       },
       plugins: [],
     }
    
  5. Next, re-run the following command again to start your Vite app

    Vite will launch the development server, and your React app will be available at http://127.0.0.1:5173 by default:

      npm run dev
    

Implementing routes in our application

Since you are building a multi-page application, users that visit your app will be redirected to the user page after successful registration. For this functionality, you will be using react-router-dom.

Setting up react-router-dom

  1. Install React Router:

      npm install react-router-dom
    

With the project set up and React Router installed, you can now start building your multi-page application!

Implementing Routes

In a multi-page application, you will define routes that map specific URLs to different components. These components will be rendered when the corresponding route is accessed. Open the src/main.jsx file and start by importing the necessary modules:

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import {BrowserRouter} from "react-router-dom"

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

Next, open your src/App.jsx and define routes inside the App component like this

import {Route, Routes} from "react-router-dom"
import Register from "./Register"
import Login from "./Login"
import User from "./User"
import Reset from './Reset'

function App() {

  return (
    <>
      <Routes>
        <Route path="/" element={<Login/>}/>
        <Route  path="/Register" element={<Register/>}/>
        <Route path="/user" element={<User/>}/>
        <Route path="/reset" element={<Reset/>}/>
      </Routes>
    </>
  )
}

export default App

Creating necessary Components

You will be creating four components in the react app and they will be:

  • Login Component

  • Register Component

  • User Component

  • Reset-page Component

For the Login component, create a file named login.jsx file in the src directory and paste this:

import React from "react"
import { Link } from "react-router-dom"

export default function Login() {
    return (
      <>
        <div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
          <div className="sm:mx-auto sm:w-full sm:max-w-sm">
            <h2 className="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
              Sign in to your account
            </h2>
          </div>

          <div className="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
            <form className="space-y-6" action="#" method="POST">
              <div>
                <label htmlFor="email" className="block text-sm font-medium leading-6 text-gray-900">
                  Email address
                </label>
                <div className="mt-2">
                  <input
                    id="email"
                    name="email"
                    type="email"
                    autoComplete="email"
                    required
                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>

              <div>
                <div className="flex items-center justify-between">
                  <label htmlFor="password" className="block text-sm font-medium leading-6 text-gray-900">
                    Password
                  </label>
                  <div className="text-sm">
                    <a href="#" className="font-semibold text-indigo-600 hover:text-indigo-500">
                      Forgot password?
                    </a>
                  </div>
                </div>
                <div className="mt-2">
                  <input
                    id="password"
                    name="password"
                    type="password"
                    autoComplete="current-password"
                    required
                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>

              <div>
                <button
                  type="submit"
                  className="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
                >
                  Sign in
                </button>
              </div>
            </form>

            <p className="mt-10 text-center text-sm text-gray-500">
              Don't have an account?{' '}
              <Link to={"/Register"} className="font-semibold leading-6 text-indigo-600 hover:text-indigo-500">
                Register Here
              </Link>
            </p>
          </div>
        </div>
      </>
    )
  }

it will look like so for the login page

Register Page

For the Register Page, create a file named Register.jsx in the src directory and paste this

import React from "react"
import { Link } from "react-router-dom"

export default function Register() {
    return (
      <>
        <div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
          <div className="sm:mx-auto sm:w-full sm:max-w-sm">
            <h2 className="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
              Register in to your account
            </h2>
          </div>

          <div className="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
            <form className="space-y-6" action="#" method="POST">
            <div>
                <label htmlFor="email" className="block text-sm font-medium leading-6 text-gray-900">
                 First Name
                </label>
                <div className="mt-2">
                  <input
                    id="email"
                    name="email"
                    type="email"
                    autoComplete="email"
                    required
                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>
              <div>
                <label htmlFor="email" className="block text-sm font-medium leading-6 text-gray-900">
                 Last Name
                </label>
                <div className="mt-2">
                  <input
                    id="email"
                    name="email"
                    type="email"
                    autoComplete="email"
                    required
                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>
              <div>
                <label htmlFor="email" className="block text-sm font-medium leading-6 text-gray-900">
                  Email address
                </label>
                <div className="mt-2">
                  <input
                    id="email"
                    name="email"
                    type="email"
                    autoComplete="email"
                    required
                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>

              <div>
                <div className="flex items-center justify-between">
                  <label htmlFor="password" className="block text-sm font-medium leading-6 text-gray-900">
                    Password
                  </label>
                  <div className="text-sm">
                    <Link to="/reset" className="font-semibold text-indigo-600 hover:text-indigo-500">
                      Forgot password?
                    </Link>
                  </div>
                </div>
                <div className="mt-2">
                  <input
                    id="password"
                    name="password"
                    type="password"
                    autoComplete="current-password"
                    required
                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>

              <div>
                <button
                  type="submit"
                  className="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
                >
                  Register
                </button>
              </div>

              <div className="text-sm flex flex-row gap-5">
                 <p>Already have an account? </p>
                    <Link to="/" className="font-semibold text-indigo-600 hover:text-indigo-500">
                      Login
                    </Link>
                  </div>
            </form>
          </div>
        </div>
      </>
    )
  }

Here is what it looks like

User Page

For the User Page, create a file named User.jsx in the src directory and paste this

import React, { useEffect, useState } from 'react'

const User = () => {

  return (
    <div className='flex flex-col justify-center items-center border border-[#e2e0e0] mx-10 mt-10 lg:mx-[250px] py-10'>
    <div className='flex flex-row justify-center items-center gap-6'>
     <p>Logged in as <span className='text-blue-500 font-bold'></span></p>    
    </div>
    <button className='bg-blue-500 rounded-md px-3 py-2'>
      Sign Out
    </button>
    </div>
  )

}

export default User

Reset Page

For the Reset Page, create a file named Reset.jsx in the src directory and paste this

import React from "react"
import { Link } from "react-router-dom"


export default function Reset() {
    return (
<div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
          <div className="sm:mx-auto sm:w-full sm:max-w-sm">    
            <h2 className="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
              Reset your account
            </h2>
          </div>

          <div className="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
            <form className="space-y-6">
              <div>
                <label htmlFor="email" className="block text-sm font-medium leading-6 text-gray-900">
                  Email address
                </label>
                <div className="mt-2">
                  <input
                    id="email"
                    name="email"
                    type="email"           
                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>
                <button
                  type="submit"          
                  className="flex w-full justify-center rounded-md mb-4 bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
                >
                 Reset
                </button>
            </form>

            <p className="mt-10 text-center text-sm text-gray-500">
              Don't have an account?{' '}
              <Link to={"/Register"} className="font-semibold leading-6 text-indigo-600 hover:text-indigo-500">
                Register Here
              </Link>
            </p>
          </div>
        </div>
)
}

Here is what it will look like

Why is user authentication important?

Around 33 billion account breaches are predicted to occur in 2023. Cyberattacks are becoming increasingly sophisticated, causing devastating consequences: financial and personal data loss.

Users need protection on the Internet, and user authentication is one of the most important cybersecurity bastions. It protects sensitive information and prevents unauthorized access to systems and data.

What is Firebase?
In simple words, Firebase is a software development platform that helps in building web and mobile applications with its 18 services. These 18 services of this BaaS solution also include purposeful APIs and four beta products. In addition, it is compatible to integrate with Android, web, iOS, and Unity setups.

Importance of Firebase

Firebase provides many unique features and functionalities that make it more than just a tool for authentication. Here are some of them

  • Google Analytics: Although Google Analytics is a free tool provided by Google but its integration becomes seamless when you work with Firebase. Google Analytics is compatible with iOS, Android, Web, C++, and Unity setups. This free analytic solution reports to the developers how users are behaving toward their mobile and web applications.

  • Secure and fast hosting services: Another appealing advantage of Firebase is its secure & fast hosting services. Firebase hosting supports all content types, including web applications, dynamic and static content. Moreover, whether you want to host your Express.js microservices, HTML, CSS, or APIs, the hosting support of Firebase is always there. .

  • Scalability: Though Firebase’s Realtime Database is capable of scaling, things will start to get crazy when you app becomes really popular or if your database becomes really massive.

    Getting started with Firebase

    To continue with this tutorial, you need an account with Firebase!. Create one on the Firebase website using your email address, Google account.

  1. Create a Project

    Click on Create a Project as shown in the image below

  1. Give your project a title name
    Make sure you give your Project a title name and then press continue button as shown in the image below:

3. Give your project a title name, you will be navigated to the page where you will presented a choice to enable google analytics, but it's not a necessity for this tutorial. So press continue as shown in the image

  1. Accept the Google Analytics terms
    Next, accept google analytics and click on create project

5. Creation of Project
Now your Project get created, so wait till the process is done.

  1. Click on the web icon to get started with installing firebase in our app:

Installing Firebase

Here, Add firebase to your app by following this steps:

  1. Give your app a nickname like auth-app. Next, set up firebase-hosting and then select the default site for deployment.

Next, click the register app button:

  1. Now go to your terminal, then install firebase using this command:
npm install firebase

Adding SDKs to our React app

SDKs are needed so that you can connect firebase to your application. Follow these steps to connect firebase:

1. Create a config.js file in your src directory and copy your functions you need from the SDKs like this

const firebaseConfig = {
  apiKey: "AIzaSyDK3AMzW3KgtR0dTOxwF6a5FiiOdUN3m6k",
  authDomain: "auth-app-1eedd.firebaseapp.com",
  projectId: "auth-app-1eedd",
  storageBucket: "auth-app-1eedd.appspot.com",
  messagingSenderId: "933857762305",
  appId: "1:933857762305:web:f461dbf6bf14cf38ca7400",
  measurementId: "G-YM6PQ3XPMJ"
};
  1. Here we will be able to deploy our app, but since this is not needed for this tutorial, press the continue to console button

Getting Started With Authentication

So Now after following the process, you will be taken to your project overview page, go to the sidemenu and you will see this image below.

Make sure to click on build and you will see authentication, Now click on authentication and you will be navigated to the authentication page:

Next, Press the set up sign-in method button to authenticate and manage users from a variety of providers:

After doing that, you will be given list of providers to add your sign-in method with

For this tutorial, you will be using Google and email/password as your provider.

Adding Google provider

  1. First, Click on the google provider button

  2. Now, Click on the enable button to ensure you put your Public-facing name for your project and provide your support email. Next, Click on the save button at the bottom.

Here you have successfully enabled the google Provider for authentication.

Adding Email/Password native providers

After enabling google Provider, follow this steps to add email/password Providers

1. Click on the add new provider button.

Next, Pick Email/Password as the next Provider:

  1. Enable for only Email/password and not Email link and then click save to continue the Process

Congratulations, you have also successfully added email/password Providers

Configuring authorized domains

Why is it important?
When you use a custom domain with Firebase, you need to reconfigure authorized domains to allow secure communication between your domain and Firebase services.This ensures that your custom domain can interact with your Firebase project's resources.

Firebase won't work properly with your domain without adding your custom domain to the authorized domains list. So, it's a necessary step to make everything work smoothly and securely!

Here are the steps to create a custom domain

  1. Go to the settings tab and click on Authorized domains

  2. Next, click on add domain and put 127.0.0.1 as the custom domain since our React app is on port http://127.0.0.1:5173 and then press add to save the custom domain

    After adding, we successfully set up custom domain authorization.

What is Cloudstore ?

Cloud Firestore is a scalable and flexible NoSQL database provided by Firebase, a Google Cloud service. It is designed to store and synchronize data in real-time for iOS, Android, and web applications.

Enabling CloudStore

1. Click on Build and then on Firestore Database on the left-side menu

  1. Next , Click Create database

  1. Now this modal shows after, you are expected to start in test mode. The test mode is more permissive, allowing all read and write operations, which helps during the development and testing phase. Now Press Next to start in test mode.

  1. Here, Set your cloud firestore location
    Next, Press enable to complete the Process.

Creating a collection for the document

After setting your Cloud firestore location, follow these steps to create a collection where you store your data:

  1. Click Start collection like in the image below:

  1. Make sure you put in your collection ID name which is the specified name for the collection and press next

  1. After creating a name for your collection, press the auto id button so that you get your Document ID by default.

Next, create your first document by putting a key in your field and then giving it a value:

  1. After that, click save and your database is ready to go.

Finalizing the App Authentication

Now, Go back to your config.js fille in your src folder where you have your SDKs:

//config.js file
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import {getAuth} from "firebase/auth"
import {getFirestore} from "firebase/firestore"
const firebaseConfig = {
  apiKey: "AIzaSyDK3AMzW3KgtR0dTOxwF6a5FiiOdUN3m6k",
  authDomain: "auth-app-1eedd.firebaseapp.com",
  projectId: "auth-app-1eedd",
  storageBucket: "auth-app-1eedd.appspot.com",
  messagingSenderId: "933857762305",
  appId: "1:933857762305:web:f461dbf6bf14cf38ca7400",
  measurementId: "G-YM6PQ3XPMJ"
};
  • After importing your functions from the SDKs, you stiil have to initialize firebase and cloud firestore into our project. To do that, copy these block of code into the config.js file
// Initialize Firebase
export const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const db = getFirestore(app); // Initialize Cloud Firestore and get a reference to the service
  • Next, Create a context.js file .

    it is assumed you have a basic knowledge of useContext hook in react.

    A context file is, where you create a React context and a central place where you define the data that you want to share across components in your application.

    you will share functionalities created across your app that simply help you to login in with Google, log in with an email and password and sign up with an email and password.

Here is an example of a basic context.js file

//context.js file
import React, { useContext } from "react";


const AuthContext = React.createContext();// Creating a context in React

export const AuthProvider = ({ children }) => {
  return <AuthContext.Provider value={"data"}>
    {children}
  </AuthContext.Provider>;
};

export const useGlobalContext = () => {
  return useContext(AuthContext);
};

Let's break this down

  • The AuthProvider component is responsible for providing the data to consuming components It takes a "children" prop, which represents the child components that will receive the context data
export const AuthProvider = ({ children }) => {
  return <AuthContext.Provider value={"data"}>
    {children}
  </AuthContext.Provider>;
};
  • The useGlobalContext custom hook, which simplifies consuming the AuthContext data in components. Components can use this hook to access the data from the AuthProvider
export const useGlobalContext = () => {
  return useContext(AuthContext);
};

So we go to our main.js file and we import our AuthProvider which you will be using to wrap your App like this:

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import {BrowserRouter} from "react-router-dom"
import { AuthProvider } from './Context.jsx'
ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
  <AuthProvider>
  <BrowserRouter>
    <App />
  </BrowserRouter>
  </AuthProvider>
  </React.StrictMode>,
)

Inside your context.js file, you will create your authentication functions inside your AuthProvider which will help you to sign in to the users page using your Google account, then log in using your email and password and sign up with your email and password.

googleSignin function

The googleSignin function facilitates Google sign-in for users using Firebase Authentication. If the user signs in successfully and is not already registered in the Firestore "users" collection, it creates a new document with the user's information. If the user is already registered, it does not create a duplicate entry. This function helps manage user authentication and registration using Google sign-in a Firebase-powered application:

//our googleLogin Function
    const googleLogin = async() => {  
    try {
        const provider = new GoogleAuthProvider()
         const response = await signInWithPopup(auth, provider)
        const user = response.user
        console.log(user)
        const userRef = (collection(db, "users"))
        console.log(userRef)
        //Cloud Firestore provides powerful query functionality for specifying which documents you want to retrieve from a collection or collection group.
      if(user) {
        const querySnapShot =  query(userRef, where("uid", "==", user.uid))
        const userInfo  = getDoc(querySnapShot)
        if (userInfo.docs.length == 0) { // meaaning if the user doesn't exist on the document
            await addDoc(collection(db, "users"), { // Hence, Create user with the parameters
              uid: user.uid,
              name: user.displayName,
              email: user.email,
            });
          }

      }
    } catch (error) {
        throw new Error(error)
    }

}

loginEmailAndPassword function

The loginEmailAndPassword function is an asynchronous function that handles the login process using email and password with Firebase Authentication:

// loginEmailAndPassword function
 const loginEmailAndPassword = async (email, password) => {
    try {
       const response = await signInWithEmailAndPassword(auth, email, password)
       console.log(response)
    } catch (error) {
        throw new Error(error)
    }
}

signUpEmailAndPassword Function

The signUpEmailAndPassword function is a part of the user registration (sign-up) process in a web application that utilizes Firebase Authentication and Cloud Firestore. The purpose of this function is to allow users to create an account using their email and password.

 //signUpEmailAndPassword function
 const signUpEmailAndPassword = async (name, email, password) => {
    try {
    const response = await createUserWithEmailAndPassword(auth, email, password)
    console.log(response.user)
    const userRef = collection(db, "users")
    console.log(userRef)
     if(!user) {
     const newUser =  await addDoc(userRef, {
       uid: user.uid,
        name,
        email: user.email,
        auth: "",
        password: user.password
       })
       return newUser
     } 
    } catch (error) {
        throw new Error (error)
    }

}

After creating the functions, pass them as a value to the Authcontext that helps in sharing them across the App:


        return <AuthContext.Provider value={{
            googleLogin,
            loginEmailAndPassword,
            signUpEmailAndPassword
            }}>
           {children}
        </AuthContext.Provider>
 }

so the context.js file finally look like this:



import { auth, db} from "./confg";
import {GoogleAuthProvider,signInWithEmailAndPassword, createUserWithEmailAndPassword, signInWithPopup} from "firebase/auth"
import {getFirestore,query,collection, where,addDoc, getDoc, getDocs} from "firebase/firestore"
import {useNavigate} from "react-router-dom"
import React, {useContext} from "react"



const AuthContext = React.createContext()

 export const AuthProvider = ({children}) => {
    const googleSigin = async() => {

    try {
        const provider = new GoogleAuthProvider()
         const response = await signInWithPopup(auth, provider)
        const user = response.user
          console.log(user)
        const userRef = (collection(db, "users"))
        console.log(userRef.firestore)
        const querySnapshot = await getDocs(userRef);

        querySnapshot.forEach((doc) => {
          console.log(doc.id, "=>", doc.data());
        });
        //Cloud Firestore provides powerful query functionality for specifying which documents you want to retrieve from a collection or collection group.
      if(user) {
        const querySnapShot =  query(userRef, where("uid", "==", user.uid))
        const userInfo  = getDoc(querySnapShot)
        if (userInfo.docs.length == 0) { // meaaning if the user doesn't exist on the document
            await addDoc(collection(db, "users"), { // Hence, Create user with the parameters
              uid: user.uid,
              name: user.displayName,
              email: user.email,
            });
          }

      }
    } catch (error) {
        throw new Error(error)
    }

}

  const loginEmailAndPassword = async (email, password) => {
    try {
       const response = await signInWithEmailAndPassword(auth, email, password)
       console.log(response)
    } catch (error) {
        throw new Error(error)
    }

}

 const signUpEmailAndPassword = async (name, email, password) => {
    try {
    const response = await createUserWithEmailAndPassword(auth, email, password)
    console.log(response.user)
    const userRef = collection(db, "users")
    console.log(userRef)
    if(!response.user) {
     const newUser =  await addDoc(userRef, {
        uid: user.uid,
        name,
        email: user.email,
        auth: "",
        password: user.password
      })
      return newUser
    } 
    navigate("/user")

    } catch (error) {
        throw new Error (error)
    }

}
        return <AuthContext.Provider value={{
            googleLogin,
            loginEmailAndPassword,
            signUpEmailAndPassword
            }}>
           {children}
        </AuthContext.Provider>
 }

export const useGlobalContext = () => {
    return useContext(AuthContext)
}

Implementation inside the login component

Inside your login component, make all the necessary imports

import { useGlobalContext } from "./Context"
import {useNavigate} from "react-router-dom"

you copy this block of code inside your login function:

 const [email, setEmail] = useState("")
  const [password, setPassword] = useState("")
  const [error, setError] = useState("")

//we call the useGloblalContext function and import our functionalties 
  const {googleLogin, loginEmailAndPassword} = useGlobalContext()

  const navigate = useNavigate()

Here are the things to note in the implementation:

  • usestate holds the value for the email, password and error

        const [email, setEmail] = useState("")
        const [password, setPassword] = useState("")
        const [error, setError] = useState("")
    
  • useGlobalContext is called so that you have access to your googleLogin and loginEmailandPassword functionalities.

const {googleLogin, loginEmailAndPassword} = useGlobalContext()
  • when the useNavigate function is called, it helps you navigate to the users page when you login successfully.

       const navigate = useNavigate()
    

After you handle the form inputs and button click, this is how your layout for the login component should look like :

  import React, {useState, useEffect} from "react"
import { auth, db} from "./confg";
import { Link } from "react-router-dom"
import {useNavigate} from "react-router-dom"
import {FaGoogle} from "react-icons/fa"
import { useGlobalContext } from "./Context"
import {useAuthState} from "react-firebase-hooks/auth"

export default function Login() {
  const {googleLogin, loginEmailAndPassword} = useGlobalContext()
  const [user] = useAuthState(auth)
  const navigate = useNavigate()
  const [email, setEmail] = useState("")
  const [password, setPassword] = useState("")
  const [error, setError] = useState("")

   const Login = async (e) => {
    e.preventDefault()   
    try {

      if(!email && !password) {
        setError("Fill in all details")
      }
      await loginEmailAndPassword(email, password)
    } catch (error) {
         setError("There is error logging in")
        throw new Error (error)
    }
   }

   const handlerGoogleLogin = async (e) => {
       e.preventDefault()
       try {
        const response =  await googleLogin()
        console.log(response)
        navigate("/user")
       }
       catch (error) {
        throw new Error(error)
       }

   }


   useEffect(() => {
    let TimeoutId
    if(error) {
      TimeoutId = setTimeout(() => { 
        setError("")
    },2000)
    }
    if(user) {
      navigate("/user")
    }
    return () => {
      clearTimeout(TimeoutId)
    }

  },[error, user])
    return (
      <>
        <div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
          <div className="sm:mx-auto sm:w-full sm:max-w-sm">
          <span className="text-red-300">{error}</span>
            <h2 className="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
              Sign in to your account
            </h2>
          </div>

          <div className="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
            <form className="space-y-6">
              <div>
                <label htmlFor="email" className="block text-sm font-medium leading-6 text-gray-900">
                  Email address
                </label>
                <div className="mt-2">
                  <input
                    id="email"
                    name="email"
                    type="email"
                    value={email}
                    onChange={(e) => setEmail(e.target.value)}
                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>

              <div>
                <div className="flex items-center justify-between">
                  <label htmlFor="password" className="block text-sm font-medium leading-6 text-gray-900">
                    Password
                  </label>
                  <div className="text-sm">
                    <Link to="/reset" className="font-semibold text-indigo-600 hover:text-indigo-500">
                      Forgot password?
                    </Link>
                  </div>
                </div>
                <div className="mt-2">
                  <input
                    id="password"
                    name="password"
                    type="password"
                    value={password}
                    onChange={(e) => setPassword(e.target.value)}
                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>

              <div>
                <button
                  type="submit"
                   onClick={Login}
                  className="flex w-full justify-center rounded-md mb-4 bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
                >
                  Sign in
                </button>
                <button
                  type="submit"
                  onClick={handlerGoogleLogin}
                  className="flex w-full justify-center items-center gap-5 rounded-md bg-[#FFF] px-3 py-1.5 text-sm font-semibold leading-6 shadow-sm  focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
                >
                  Sign in with google
                 <span className="text-blue-600"><FaGoogle/></span> 
                </button>
              </div>
            </form>

            <p className="mt-10 text-center text-sm text-gray-500">
              Don't have an account?{' '}
              <Link to={"/Register"} className="font-semibold leading-6 text-indigo-600 hover:text-indigo-500">
                Register Here
              </Link>
            </p>
          </div>
        </div>
      </>
    )
  }

implementation for the signUp component

You do all the necessary imports, just like it is done below:

import { useGlobalContext } from "./Context"
import {useNavigate} from "react-router-dom"

Now copy this block of code inside the login function:

const navigate = useNavigate()
   const {signUpEmailAndPassword} = useGlobalContext()
  const [name, setName] = useState("")
  const [email, setEmail] = useState("")
  const [password, setPassword] = useState("")
  const [error, setError] = useState("")

  const registerAccount = (e) => {
    e.preventDefault()
    if(!name | !email | !password) {
        setError("Kindly Fill in all details")
        return;
    }
       const success = signUpEmailAndPassword(name, email, password)
       if(success){
        navigate("/user")
      }
  }

  useEffect(() => {
    let TimeoutId
    if(error) {
      TimeoutId = setTimeout(() => { 
        setError("")
    },1000)
    }
    return () => {
      clearTimeout(TimeoutId)
    }

  },[error])

Here are the things to note in the implementation:

  • The usestate holds the value for the name, email, error and password.

        const [name, setName] = useState("")
        const [email, setEmail] = useState("")
        const [password, setPassword] = useState("")
        const [error, setError] = useState("")
    
  • useGlobalContext is called so that you access the signUpEmailandPassword functionality.

 const {signUpEmailAndPassword} = useGlobalContext()
  • useNavigate is what helps you to navigate to your users page after users signUp .
const navigate = useNavigate()
  • The registerAccount function helps in checking if there is name, email, or password before allowing users to signup.
  const registerAccount = (e) => {
    e.preventDefault()
    if(!name | !email | !password) {
        setError("Kindly Fill in all details")
        return;
    }
       const success = signUpEmailAndPassword(name, email, password)
       if(success){
        navigate("/user")
      }
  }
  • The useEffect hook helps in clearing up the error state in 1 second if there is error and we pass the error as a dependency.

N.B

Dependencies in the useEffect dependency array [error] indicate that the effect will be re-run whenever the error state change. This ensures that if any relevant data changes (e.g., the user logs in or out), the effect will respond accordingly

useEffect(() => {
    let TimeoutId
    if(error) {
      TimeoutId = setTimeout(() => { 
        setError("")
    },1000)
    }
    return () => {
      clearTimeout(TimeoutId)
    }

  },[error])

After the implementation and handling of the form inputs, button clicks , necessary methods to sign up the user, here is how your layout for the register component should look like :

 import React, {useEffect, useState} from "react"
import { Link } from "react-router-dom"
import { useGlobalContext } from "./Context"
import {useNavigate} from "react-router-dom"
import { useAuthState } from "react-admin"
import { auth } from "./confg"
export default function Register() {

  const navigate = useNavigate()

   const { registerWithEmailAndPassword } = useGlobalContext()

   const [user] = useAuthState(auth)

  const [name, setName] = useState("")
  const [email, setEmail] = useState("")
  const [password, setPassword] = useState("")
  const [error, setError] = useState("")

  const registerAccount = (e) => {
    e.preventDefault()
    try {
       if(!name | !email | !password) {
        setError("Kindly Fill in all details")
        return;
    }
       registerWithEmailAndPassword(name, email, password)

    } catch (error) {
      setError("There is error logging in")
      throw new Error (error)
    }

  }

  useEffect(() => {
    let TimeoutId
    if(error) {
      TimeoutId = setTimeout(() => { 
        setError("")
    },1000)
    }
    if(!user){
      navigate("/")
    }
    return () => {
      clearTimeout(TimeoutId)
    }

  },[error, user])

    return (
      <>
        <div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
          <div className="sm:mx-auto sm:w-full sm:max-w-sm">
            <span className="text-red-300">{error}</span>
            <h2 className="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
              Register in to your account
            </h2>
          </div>

          <div className="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
            <form className="space-y-6">
            <div>
                <label htmlFor="name" className="block text-sm font-medium leading-6 text-gray-900">
                 Name
                </label>
                <div className="mt-2">
                  <input
                    name="name"
                    type="name"
                    value={name}
                    onChange={(e) => setName(e.target.value)}


                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>
              <div>
                <label htmlFor="email" className="block text-sm font-medium leading-6 text-gray-900">
                  Email address
                </label>
                <div className="mt-2">
                  <input
                    id="email"
                    name="email"
                    type="email"
                    value={email}
                    onChange={(e) => setEmail(e.target.value)}
                    autoComplete="email"

                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>

              <div>
                <div className="flex items-center justify-between">
                  <label htmlFor="password" className="block text-sm font-medium leading-6 text-gray-900">
                    Password
                  </label>
                  <div className="text-sm">
                    <a href="#" className="font-semibold text-indigo-600 hover:text-indigo-500">
                      Forgot password?
                    </a>
                  </div>
                </div>
                <div className="mt-2">
                  <input
                    id="password"
                    name="password"
                    type="password"
                    value={password}
                    onChange={(e) => setPassword(e.target.value)}
                    autoComplete="current-password"

                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>

              <div>
                <button
                  type="submit"
                  className="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
                  onClick={registerAccount}
                >
                  Register
                </button>
              </div>

              <div className="text-sm flex flex-row gap-5">
                 <p>Already have an account? </p>
                    <Link to="/" className="font-semibold text-indigo-600 hover:text-indigo-500">
                      Login
                    </Link>
                  </div>
            </form>
          </div>
        </div>
      </>
    )
  }

Implementation for the user component

  1. Make all the necessary imports:
import React, { useEffect, useState } from 'react'
import {auth} from "./config"
import {useAuthState} from "react-firebase-hooks/auth"
import {signOut} from "firebase/auth"
import {useNavigate} from "react-router-dom"
  1. Copy this block of code inside your login function:
  const [loading, setLoading] = useState("")
  const [userInfo, setUserInfo] = useState([])
  const[username, setUsername] = useState("")
  const[useremail, setUseremail] = useState("")

  const navigate = useNavigate()

  const [user] = useAuthState(auth)

const fetchSpecificUser = async () => {
      const userRef = collection(db, "users")
      const querySnapshot = query (userRef, where("email", "==", user?.email))
      const doc = await getDocs(querySnapshot)
      const {name, email} = (doc?.docs[0]?.data())
      setUsername(name)
      setUseremail(email)
    }

  useEffect(() => {

    if(!user) {  // -> if no user exists
      navigate("/") 
   }

      fetchSpecificUser()

      let intervalId
      if(!username){  // if no username exists
        intervalId = setTimeout(() => {
           fetchSpecificUser()
        },5000)
      }
  },[user, username, loading, setLoading])

  const handleSignOut = async() => {
    await signOut(auth)
    navigate("/")
  }

Here are the things to note in the implementation:

  • The usestate holds the value for the loading, userInfo, username, and userEmail state.
  const [loading, setLoading] = useState("")
  const [userInfo, setUserInfo] = useState([])
  const[username, setUsername] = useState("")
  const[userEmail, setUseremail] = useState("")
  • The useNavigate function is called when we need to redirect back to our login page
const navigate = useNavigate()

we call the useAuthstate function while passing auth as it's only parameters, to get the user data from firebase.

const [user] = useAuthState(auth)
  • The fetchSpecificUser function is an asynchronous function that fetches specific user data from a Firebase Firestore database based on the user's email. Here's a brief explanation of what the function does:

    1. It first creates a reference to the "users" collection in the Firestore database using collection(db, "users").
    const fetchSpecificUser = async () => {
          const userRef = collection(db, "users")
      }
  1. Next, it creates a query to retrieve documents from the "users" collection where the "email" field matches the email of the current user (user?.email). The where function is used to specify the condition for the query. It then executes the query and awaits the result using getDocs(querySnapshot), which returns a QuerySnapshot containing the matching documents
    const fetchSpecificUser = async () => {
          const userRef = collection(db, "users")
          const querySnapshot = query (userRef, where("email", "==", user?.email))
          const doc = await getDocs(querySnapshot)
        }
  1. The function then extracts the name and email fields from the first document in the query result (if any) using doc?.docs[0]?.data(). The optional chaining (?.) is used to handle cases where the query might not return any results or if there's an error, it sets the name and email values retrieved from the document.

       const fetchSpecificUser = async () => {
           const userRef = collection(db, "users")
           const querySnapshot = query (userRef, where("email", "==", user?.email))
           const doc = await getDocs(querySnapshot)
         const {name, email} = (doc?.docs[0]?.data())
           setUsername(name)
           setUseremail(email)
         }
    
  • The useEffect hook checks if no user exists before updating the loading state, here let look at what the useEffect does:

    1. This condition below checks if there is no user currently logged in. If user does not exist, then there is a redirect back to the login page. But if there is a user, the fetchSpecificUser() function is invoked.
useEffect(() => {

    if(!user) {  // -> if no user exists
      navigate("/")
    }
  fetchSpecificUser()


  },[ user, username, loading, setLoading ])
  • Here the code checks if username exists, indicating that the username data hasn't been fetched yet or is not available. If so, it sets up a timeout using setTimeout. After 5 secs, it invokes fetchSpecificUser() again. This means that if the username data is not available initially, the component will re-fetch the user data after a short delay.
useEffect(() => {

    if(!user) { 
     navigate("/")
    }

      fetchSpecificUser()

      let intervalId
      if(!username){  // if no username exists it sets up a timeout
        intervalId = setTimeout(() => {
           fetchSpecificUser() // it invokes fetchSpecificUser again
        },5000)
      }
  },[user, username, loading, setLoading])
  • handleSignOut function: This function is an asynchronous function that handles the user sign-out process. It calls the signOut function from the Firebase auth module to sign the user out. After successfully signing out, it uses the navigate function to navigate the user to the login page
  const handleSignOut = async() => {
    await signOut(auth)
    navigate("/")
  }

Dependencies in the useEffect dependency array [user, username, loading, setLoading] indicate that the effect will be re-run whenever any of these variables change. This ensures that if any relevant data changes (e.g., the user logs in or out), the effect will respond accordingly.

After the implementation and handling the user, loading state, form inputs, button clicks, and necessary methods to sign up the user, here is how your layout for the user component should look like :

    import React, { useEffect, useState } from 'react'
import {auth, db} from "./confg"
import {useAuthState} from "react-firebase-hooks/auth"
import {signOut} from "firebase/auth"
import {useNavigate} from "react-router-dom"
import { collection, query, where, getDoc, getDocs } from 'firebase/firestore'
const User = () => {
  const [loading, setLoading] = useState("")
  const [userInfo, setUserInfo] = useState([])
  const[username, setUsername] = useState("")
  const[userEmail, setUseremail] = useState("")

  const [user] = useAuthState(auth)
  const navigate = useNavigate()
  useEffect(() => {

     const fetchSpecificUser = async () => {
      const userRef = collection(db, "users")
      const querySnapshot = query (userRef, where("email", "==", user?.email))
      const doc = await getDocs(querySnapshot)
      const {name, email} = (doc?.docs[0]?.data())
      setUsername(name)
      setUseremail(email)
    }

    if(!user) {
      navigate("/")
    }

      fetchSpecificUser()

      let intervalId
      if(!username){
        intervalId = setTimeout(() => {
           fetchSpecificUser()
        },5000)
      }
  },[user, username, loading, setLoading])

  const handleSignOut = async() => {
    await signOut(auth)
    navigate("/")
  }

  return (
    <div className='flex flex-col justify-center items-center border border-[#e2e0e0] mx-10 mt-10 lg:mx-[250px] py-10'>
    <div className='flex flex-row justify-center items-center gap-6'>
     <p>Logged in as <span className='text-blue-500 font-bold'>{username ? username : "loading"}</span></p> 

     {user?.photoURL ? 
      <img className='rounded-[100%]' src={user?.photoURL} alt='image'/>
       : ""
     }

    </div>

    <button className='bg-blue-500 rounded-md px-3 py-2' onClick={handleSignOut}>
      Sign Out
    </button>
    </div>
  )

}

export default User

Implementation for the reset component

Make you do all the necessary imports:

import { useState, useEffect } from "react";
import { auth} from "./config";
import { useGlobalContext } from "./Context";
import {useNavigate, Link} from "react-router-dom"
import {useAuthState} from "react-firebase-hooks/auth"

Inside your reset function, copy this block of code:



  const [email, setEmail] = useState("");
  const[error, setError] = useState("");

  const [user] = useAuthState(auth);
  const navigate = useNavigate();
 const {sendPasswordReset} = useGlobalContext()

  const handleReset = async (e) => {
    e.preventDefault()   
    try {

      if(!email) {
        setError("Fill in the detail")
      }
      await sendPasswordReset(email)
      alert("Password reset link sent!, check your email");
      navigate('/')

    } catch (error) {
         setError("There is error resetting your password")
        throw new Error (error)
    }
}
  useEffect(() => {

    if (user) navigate("/user");

  }, [user]);

Here are the things to note in the implementation:

  • The usestate holds the value for the email and error
  const [email, setEmail] = useState("");
  const[error, setError] = useState("");
  • we call the useGloblaobalContext hook to gain access to our sendPasswordReset functionality

      const {sendPasswordReset} = useGlobalContext()
    
  • we call the useAuthstate function while passing auth as it's only parameters, to get the user data from firebase.

const [user] = useAuthState(auth);
  • The handleReset function is the asynchronous function that helps you to reset our password. inside your handleReset function, you have your try block where you set the error state to "fill in the detail" if there is no email. But If there is email, you call the sendPasswordReset function while passing your email as the only parameter and then you navigate back to your login page. While in your catch block, set the error state and then throw the error if any:

      const handleReset = async (e) => {
          e.preventDefault()   
          try {
    
            if(!email) {
              setError("Fill in the detail")
            }
            await sendPasswordReset(email)
            alert("Password reset link sent!, check your email");
            navigate('/')
    
          } catch (error) {
               setError("There is error resetting your password")
              throw new Error (error)
          }
      }
    

    Now after the implementation, here is how your layout for the reset page will look like:

import { useState, useEffect } from "react";
import { auth} from "./confg";
import { useGlobalContext } from "./Context";
import {useNavigate, Link} from "react-router-dom"
import {useAuthState} from "react-firebase-hooks/auth"

export default function Reset() {

const {sendPasswordReset} = useGlobalContext()

  const [email, setEmail] = useState("");
  const[error, setError] = useState("");

  const [user] = useAuthState(auth);
  const navigate = useNavigate();

  const handleReset = async (e) => {
    e.preventDefault()   
    try {

      if(!email && !password) {
        setError("Fill in the detail")
      }
      await sendPasswordReset(email)
      alert("Password reset link sent!, check your email");
      navigate('/')

    } catch (error) {
         setError("There is error resetting your password")
        throw new Error (error)
    }
}
  useEffect(() => {

    if (user) navigate("/dashboard");

  }, [user]);

  return (
    <div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
          <div className="sm:mx-auto sm:w-full sm:max-w-sm">
          <span className="text-red-300">{error}</span>
            <h2 className="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
              Reset your account
            </h2>
          </div>

          <div className="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
            <form className="space-y-6">
              <div>
                <label htmlFor="email" className="block text-sm font-medium leading-6 text-gray-900">
                  Email address
                </label>
                <div className="mt-2">
                  <input
                    id="email"
                    name="email"
                    type="email"
                    value={email}
                    onChange={(e) => setEmail(e.target.value)}
                    className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  />
                </div>
              </div>
                <button
                  type="submit"
                   onClick={handleReset}
                  className="flex w-full justify-center rounded-md mb-4 bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
                >
                 Reset
                </button>
            </form>

            <p className="mt-10 text-center text-sm text-gray-500">
              Don't have an account?{' '}
              <Link to={"/Register"} className="font-semibold leading-6 text-indigo-600 hover:text-indigo-500">
                Register Here
              </Link>
            </p>
          </div>
        </div>

  )
}

Conclusion

In this article, you have learned how to implement routes in your react app, style your app with tailwind css, authenticate your react app with firebase, implemented a backend feature using cloud firestore. You can learn more about firebase from the official documentation. If you have any questions, Contact me on Twitter: @Lord__Codex.