Build Authentication Using Firebase | React | Express
Tags: webdev, tutorial, react, javascript
Published: 2022-09-12 07:03:12

Hi everyone, in this tutorial, we are going to fire up an authentication system using React, Firebase, and Express. We will also use Tailwind to create the user interface.

## Table of Contents
1. [Introduction](#introduction)
2. [React and Tailwind Set Up](#react-tailwind)
    1. [React Router](#react-router)
    2. [Register and Login Components](#register-login)
3. [Firebase Set Up](#firebase)
4. [Firebase and React Integration](#firebase-react)
    1. [React Context](#context)
    2. [Error Handling](#error)
    3. [Profile](#profile)
    4. [Logout](#logout)
5. [Enable Dark Mode](#darkmode)
6. [Navigation](#navigation)
7. [Private Route](#proute)
8. [Express Server](#express)
    1. [Express Boilerplate](#boilerplate)
    2. [Enabling Cors](#cors)
    3. [Using Environment Variables](#env)
9. [Connect with React](#express-react)
    1. [Sending Firebase Token to Express](#token)
    2. [Creating the Middleware](#middleware)
10. [Final Thoughts](#final)

## Introduction <a name="introduction"></a>

To set up a registration/authentication system, we will leverage Firebase, a Backend-as-a-Service (Baas). *What’s a BaaS?*

Cloud computing has transformed the way we use technology. The BaaS cloud service model allows developers to focus on the frontend of an application by abstracting away all the stuff that goes behind it. Through BaaS, developers outsource pre-written software for different activities such as user authentication, database management, cloud storage, hosting, push notifications, and so on. We are going to use the user authentication service provided by Firebase for this project.

**Here is the workflow:**

1. React will send a request to register and login a user to Firebase.
2. Firebase will give a token to React
3. React will use that token to send subsequent requests to an Express server.
4. The Express server will verify the token using the Firebase admin SDK and sends a response back to React.

***Quick Note:***

- *Technically you don’t need Express for this if you aren’t going to use a backend for your project. However, in our case, we need an Express server to later create the chat API endpoints and connect with MongoDB.*
- *Also,* *if you encounter any issues throughout the tutorial, you can check out the code in the [GitHub repository](https://github.com/earthcomfy/lets-chat).*

## React and Tailwind Set Up <a name="react-tailwind"></a>

Let's create a React application first. Type in the following to create a React app.

```shell
npx create-react-app frontend
```

Remove git since we won’t use it inside the frontend app. If you are on Linux, you can remove it by running this:

```shell
cd frontend
rm -rf .git
```

Alright, we are going to use Tailwind CSS to create the components, so let’s install it.

Make sure you are inside the frontend folder, open up your terminal and install [Tailwind CSS](https://tailwindcss.com/docs/guides/create-react-app)

```shell

# Installs tailwindcss and its dependencies
npm install -D tailwindcss postcss autoprefixer

# Generates tailwind.config.js and postcss.config.js files
npx tailwindcss init -p
```

Open `tailwind.config.js` and configure your template paths.

```jsx
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};
```

Open `index.css`, remove the content and add the following Tailwind directives. Check [this](https://tailwindcss.com/docs/functions-and-directives) out to learn more about these Tailwind-specific at-rules.

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

Now, let’s delete files we won’t be using. The final structure should look something like this:


![folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1yxf3fltnvr3ax2l7dj2.png)

Your `index.js` file should look like this:

```jsx
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
```

And finally to make sure everything is set up correctly, add the following to `App.js` and start the project.

```jsx
// App.js

function App() {
  return (
    <div>
      <h1 className="text-3xl font-bold underline">Hello world!</h1>
    </div>
  );
}

export default App;
```

Start the project:

```shell
npm run start
```

![hello world tailwind](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8q5kaypbmcfxsk28wkp.png)

Perfect! now inside the `src` folder, create another folder named `components`. Then, inside `components`, create a folder named `accounts` . We will put user auth-related components inside it.

Inside `accounts`, create 2 files named `Register.js` and `Login.js`

For now, put a boilerplate like the following. If you are on VSCode, you can generate this by using the `rfc` shortcut.

```jsx
// Register.js

import React from "react";

export default function Register() {
  return <div>Register</div>;
}
```

```jsx
// Login.js

import React from "react";

export default function Login() {
  return <div>Login</div>;
}
```

### React Router <a name="react-router"></a>

We will be using React router V6 for routing between different pages. Let’s go ahead and install it.

```shell
npm i react-router-dom
```

Open `App.js` and create the path for login and register.

```jsx
// App.js

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";

import Register from "./components/accounts/Register";
import Login from "./components/accounts/Login";

function App() {
  return (
    <Router>
      <Routes>
        <Route exact path="/register" element={<Register />} />
        <Route exact path="/login" element={<Login />} />
      </Routes>
    </Router>
  );
}

export default App;
```

Go to your browser and test the routes: [http://localhost:3000/login](http://localhost:3000/login) and [http://localhost:3000/register](http://localhost:3000/register)

### Register and Login Components <a name="register-login"></a>

Up until this point, we have been doing basic configuration. Let’s now get to creating the UI for account registration and login.

```jsx
// Register.js

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

export default function Register() {
  return (
    <div className="min-h-full flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
      <div className="max-w-md w-full space-y-8">
        <div>
          <h2 className="mt-4 text-3xl text-center tracking-tight font-light dark:text-white">
            Register your account
          </h2>
        </div>
        <form className="mt-8 space-y-6">
          <div className="rounded-md shadow-sm -space-y-px">
            <div>
              <input
                id="email-address"
                name="email"
                type="email"
                autoComplete="email"
                required
                className="appearance-none rounded-none relative block w-full px-3 py-2 placeholder-gray-500 rounded-t-md bg-gray-50 border border-gray-300 text-gray-900 text-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 focus:z-10 sm:text-sm"
                placeholder="Email address"
              />
            </div>
            <div>
              <input
                id="password"
                name="password"
                type="password"
                autoComplete="current-password"
                required
                className="appearance-none rounded-none relative block w-full px-3 py-2 placeholder-gray-500 rounded-t-md bg-gray-50 border border-gray-300 text-gray-900 text-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 focus:z-10 sm:text-sm"
                placeholder="Password"
              />
            </div>
            <div>
              <input
                id="confirmPassword"
                name="confirmPassword"
                type="password"
                autoComplete="current-password"
                required
                className="appearance-none rounded-none relative block w-full px-3 py-2 placeholder-gray-500 rounded-t-md bg-gray-50 border border-gray-300 text-gray-900 text-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 focus:z-10 sm:text-sm"
                placeholder="Password"
              />
            </div>
          </div>
          <div>
            <button
              type="submit"
              className=" w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-sky-800 hover:bg-sky-900"
            >
              Register
            </button>
          </div>
          <div className="flex items-center justify-between">
            <div className="text-sm">
              <Link
                to="/login"
                className="text-blue-600 hover:underline dark:text-blue-500"
              >
                Already have an account? Login
              </Link>
            </div>
          </div>
        </form>
      </div>
    </div>
  );
}
```

- We have 3 fields. One for Email, the other two for password and password confirmation respectively. And for `Login.js` we have 2 fields; Email and password.

```jsx
// Login.js

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

export default function Login() {
  return (
    <div className="min-h-full flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
      <div className="max-w-md w-full space-y-8">
        <div>
          <h2 className="mt-4 text-3xl text-center tracking-tight font-light dark:text-white">
            Login to your account
          </h2>
        </div>
        <form className="mt-8 space-y-6">
          <div className="rounded-md shadow-sm -space-y-px">
            <div>
              <input
                id="email-address"
                name="email"
                type="email"
                autoComplete="email"
                required
                className="appearance-none rounded-none relative block w-full px-3 py-2 placeholder-gray-500 rounded-t-md bg-gray-50 border border-gray-300 text-gray-900 text-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 focus:z-10 sm:text-sm"
                placeholder="Email address"
              />
            </div>
            <div>
              <input
                id="password"
                name="password"
                type="password"
                autoComplete="current-password"
                required
                className="appearance-none rounded-none relative block w-full px-3 py-2 placeholder-gray-500 rounded-t-md bg-gray-50 border border-gray-300 text-gray-900 text-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 focus:z-10 sm:text-sm"
                placeholder="Password"
              />
            </div>
          </div>
          <div>
            <button
              type="submit"
              className=" w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-sky-800 hover:bg-sky-900"
            >
              Login
            </button>
          </div>
          <div className="flex items-center justify-between">
            <div className="text-sm">
              <Link
                to="/register"
                className="text-blue-600 hover:underline dark:text-blue-500"
              >
                Don't have an account? Register
              </Link>
            </div>
          </div>
        </form>
      </div>
    </div>
  );
}
```

Don’t worry about the classes of the elements that are prefixed with `dark`. We will talk about them later when we enable dark mode.

Let’s now use the `useState` hook to store the form data. Inside `Register.js`, import `useState` at the top and add the following 3 states.

```jsx
import { useState } from "react";

const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
```

Then, add an `onChange` event listener to the input fields as follows.

```jsx
onChange={(e) => setEmail(e.target.value)}
onChange={(e) => setPassword(e.target.value)}
onChange={(e) => setConfirmPassword(e.target.value)}
```

We now need a function that will handle the form submission.

```jsx
async function handleFormSubmit(e) {
    e.preventDefault();

    // Here We will get form values and 
		// invoke a function that will register the user
}
```

Add the function as an `onSubmit` event listener to the form.

```jsx
onSubmit={handleFormSubmit}
```

Do the same thing for `Login.js`. The only difference is that we don’t have a confirm password input field. The rest is the same. Now that our forms are ready, let’s move our attention to Firebase.

## Firebase Set Up <a name="firebase"></a>

If it’s your first time using Firebase, follow the following steps to create a project. Otherwise, you can move to the [next section](#firebase-react).

We first need to create a Firebase project using the [Firebase console](https://console.firebase.google.com/), so Log in and then click **Create a project**.


![Firebase set up](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7d954bbss0klgc5yt27c.png)

Give any name you like for the project and click **Continue.** You will then be prompted to enable Google Analytics for your project (optional). We don’t need that.

Once you have completed the steps, you will be presented with a Dashboard. Click on **Authentication** from the navigation panel and go to the **Sign-in Method** tab. Enable **Email/Password** method since that’s what we are going to use.

## Firebase and React Integration <a name="firebase-react"></a>

For React to communicate with Firebase services, we need to install the `firebase` package.

```shell
npm i firebase
```

After you have created a new project in Firebase, you need to create an application. Go to your Firebase Console dashboard, click on **Project Settings**, and select this icon (</>) to add Firebase to your web app. Doing so will give you config data.

Create a `.env` file inside the root directory of your project and store all these config data in it.

```jsx
// .env

REACT_APP_FIREBASE_API_KEY = 
REACT_APP_FIREBASE_AUTH_DOMAIN = 
REACT_APP_FIREBASE_PROJECT_ID = 
REACT_APP_FIREBASE_STORAGE_BUCKET = 
REACT_APP_FIREBASE_MESSAGING_SENDER_ID = 
REACT_APP_FIREBASE_APP_ID = 
```

- When setting up environment variables, you should prefix them with `REACT_APP_`. In addition,  make sure to put the `.env` file in your **root** folder. Finally, restart your server for the changes to take place.

Inside the `src` folder, create a folder called `config` and inside it, create a file called `firebase.js` This is where we will set up Firebase.

```jsx
// firebase.js

import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
  authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
  storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_FIREBASE_APP_ID,
};

const app = initializeApp(firebaseConfig);

// gives us an auth instance
const auth = getAuth(app);

// in order to use this auth instance elsewhere
export default auth;
```

Now that we have Firebase setup, we can start doing authentication.

### React Context <a name="context"></a>

We are going to use **React context** to set up the authentication because we want to access the current user everywhere in our app. If you aren’t familiar with React context, don’t worry. We are going to walk through it together.

React context allows us to share data (state) across our components more easily. This is great when you are passing data that can be used in any component of your application.

Inside the `src` folder, create a folder named `contexts` and inside it, create a file named `AuthContext.js` and put the following to set up context.

```jsx
// AuthContext.js

import { createContext, useContext } from "react";

const AuthContext = createContext();

export function useAuth() {
  return useContext(AuthContext);
}

export function AuthProvider({ children }) {
  const value = {};

  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  );
}
```

What is going on? Well, let me explain

- `const AuthContext = createContext()` will return a **Consumer** and a **Provider** component. **Provider** provides state to its children. It takes in the `value` prop and passes it down to its children components that might need to access them. The **Consumer** consumes and uses the state passed down to it by the **Provider**.
- In the above case, the component that will wrap the Provider is `AuthProvider` We also exported it, so that we can use it elsewhere.
- The custom `useAuth` hook will allow us to consume context in our application by returning a `useContext` instance of `AuthContext`

That is the basic setup for context. Let’s now add Firebase [functions](https://firebase.google.com/docs/auth/web/password-auth#create_a_password-based_account) to register, login, and find the current user.

First, import `createUserWithEmailAndPassword` and `signInWithEmailAndPassword` that Firebase provides for user registration and login. Also, import `auth` from our earlier Firebase configuration.

```jsx
// AuthContext.js

import {
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
} from "firebase/auth";

import auth from "../config/firebase";
```

Users can create a new account by passing their email address and password. The functions return a Promise and we will consume that inside the register and login components.

```jsx
function register(email, password) {
   // If the new account was created, the user is signed in automatically.
   return createUserWithEmailAndPassword(auth, email, password);
}

function login(email, password) {
   return signInWithEmailAndPassword(auth, email, password);
}
```

Alright, *but how can we get the signed-in user details?* We can set an observer on the `auth` object. Before that, however, let’s first create a state that will store the current user and pass it down in the `value` props.

```jsx
import { useState } from "react";
const [currentUser, setCurrentUser] = useState();

const value = {
    currentUser,
};
```

We can now set the `onAuthStateChanged` observer on the `auth` object. This will notify us when the user is signed in and update the state.

```jsx
import { useEffect } from "react";

const [loading, setLoading] = useState(true);

useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((user) => {
      setCurrentUser(user);
      setLoading(false);
    });

    return unsubscribe;
}, []);

return (
    <AuthContext.Provider value={value}>
      {!loading && children}
    </AuthContext.Provider>
);
```

- The observer i.e. `onAuthStateChanged` is put inside a `useEffect` because we only want to render it once i.e. when the component mounts. When the component un-mounts, we unsubscribe from the event.
- The `loading` state is initially set to `true`. When Firebase finishes its job and updates the user, we set it to false. This will prevent the children components from rendering while the action is taking place.

The final code for `AuthContext.js` should look like this:

```jsx
// AuthContext.js

import { createContext, useContext, useState, useEffect } from "react";
import {
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
} from "firebase/auth";

import auth from "../config/firebase";

const AuthContext = createContext();

export function useAuth() {
  return useContext(AuthContext);
}

export function AuthProvider({ children }) {
  const [currentUser, setCurrentUser] = useState();
  const [loading, setLoading] = useState(true);

  function register(email, password) {
    return createUserWithEmailAndPassword(auth, email, password);
  }

  function login(email, password) {
    return signInWithEmailAndPassword(auth, email, password);
  }

  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((user) => {
      setCurrentUser(user);
      setLoading(false);
    });

    return unsubscribe;
  }, []);

  const value = {
    currentUser,
    login,
    register,
  };

  return (
    <AuthContext.Provider value={value}>
      {!loading && children}
    </AuthContext.Provider>
  );
}
```

Let’s now wrap our components inside of the `AuthProvider` so that we have access to the context.

```jsx
// App.js

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";

import { AuthProvider } from "./contexts/AuthContext"; // import this
import Register from "./components/accounts/Register";
import Login from "./components/accounts/Login";

function App() {
  return (
    <AuthProvider> // Wrap everything inside this provider
      <Router>
        <Routes>
          <Route exact path="/register" element={<Register />} />
          <Route exact path="/login" element={<Login />} />
        </Routes>
      </Router>
    </AuthProvider>
  );
}

export default App;
```

Now, to use the `register` and `currentUser` context, head over to `Register.js` and import the `useAuth` hook.

```jsx
// Register.js

import { useAuth } from "../../contexts/AuthContext";
```

Then, import `useEffect` and `useNavigate` and add the following:

```jsx
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";

const navigate = useNavigate();
const { currentUser, register } = useAuth();
const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (currentUser) {
      navigate("/");
    }
  }, [currentUser, navigate]);
```

- `const navigate = useNavigate();` React router hook that returns a function to navigate programmatically.
- `const { currentUser, register } = useAuth();` gets the `currentUser` and `register` contexts since those are what we will be using.
- The `loading` state will be used to disable the button when the registration action is executing.
- The `useEffect` hook is in place to prevent users from accessing the registration page while they are authenticated. It will redirect them to the home page if they try to do so.

Then inside the `handleFormSubmit` function we created earlier, we are going to handle the registration logic:

```jsx
async function handleFormSubmit(e) {
    e.preventDefault();

    if (password !== confirmPassword) {
      return alert("Passwords do not match");
    }

    try {
      setLoading(true);
      await register(email, password);
      navigate("/profile");
    } catch (e) {
      alert("Failed to register");
    }

    setLoading(false);
  }
```

- First, if the passwords don’t match we exit out of the function by alerting the error. For now, we are not managing the errors. Later, however, we will handle them using a state.
- The `register` function returns a promise, so we are using the `await` keyword to wait for the call to be settled. And we are using the `try…catch` block for error handling. If the call is successful, the user will be redirected to the profile page (we haven’t created it yet). However, the flow will be sent to the `catch` block if it fails.

To disable the submit button when the action is executing, add  `disabled={loading}` to the submit `Button`.

Cool! let’s test what we have so far. Start your server and go to [http://localhost:3000/register](http://localhost:3000/register) and fill in the form with passwords that don’t match. You should get the following alert:


![firebase login](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0hfalwwwupnnmbg2agu0.png)

Now, fill in the correct credentials and you should be redirected to [http://localhost:3000/profile](http://localhost:3000/profile). However, since we haven’t created this route yet, nothing will be displayed.

Do the same thing for the `Login.js` component. You only need to change the `register` call to `login` and remove the password confirmation check.

### Error Handling <a name="error"></a>

We want to use a single component that will handle and display errors (if there are any). For this, let’s use context.

Go to `AuthContext.js` and create this state:

```jsx
const [error, setError] = useState("");
```

Add it to the `value` props:

```jsx
const value = {
    error,
    setError,
};
```

Inside components, create a folder named `layouts`. And inside it, create a file called `ErrorMessage.js` We will use this component to display error messages from anywhere in our app.

First, let’s install [herocions](https://heroicons.com/) to use the **`X`** icon in our alert.

```shell
npm i @heroicons/react@v1
```

Then inside `ErrorMessage.js`:

```jsx
// ErrorMessage.js

import { XCircleIcon } from "@heroicons/react/solid";

import { useAuth } from "../../contexts/AuthContext";

export default function ErrorMessage() {
  const { error, setError } = useAuth();

  return (
    error && (
      <div className="flex justify-center">
        <div className="rounded-md max-w-md w-full bg-red-50 p-4 mt-4">
          <div className="flex">
            <div className="flex-shrink-0">
              <XCircleIcon
                onClick={() => setError("")}
                className="h-5 w-5 text-red-400"
                aria-hidden="true"
              />
            </div>
            <div className="ml-3">
              <h3 className="text-sm font-medium text-red-800">
                Error: {error}
              </h3>
            </div>
          </div>
        </div>
      </div>
    )
  );
}
```

- The above snippet checks if there is an error and displays it. When the `X` icon is clicked it will set the error to an empty string.

Then render this component inside `App.js` at the top.

```jsx
import ErrorMessage from "./components/layouts/ErrorMessage"; // add this import

<AuthProvider>
      <Router>
        <ErrorMessage /> // add this
        <Routes>
          <Route exact path="/register" element={<Register />} />
          <Route exact path="/login" element={<Login />} />
        </Routes>
      </Router>
    </AuthProvider>
```

Now, let’s update `Register.js` to set the errors accordingly.

```jsx
const { currentUser, register, setError } = useAuth(); // Get setError as well
```

```jsx
async function handleFormSubmit(e) {
    e.preventDefault();

    if (password !== confirmPassword) {
      return setError("Passwords do not match"); // Replace the alert with this
    }

    try {
      setError(""); // Remove error when trying to register
      setLoading(true);
      await register(email, password);
      navigate("/profile");
    } catch (e) {
      setError("Failed to register"); // Replace the alert with this
    }

    setLoading(false);
  }
```

Do the same thing for `Login.js` and test it. Before testing it though, make sure to comment out the `useEffect` hook that checks if there is a current user so that it won’t redirect you to the home page.

You should get something like this:


![Error handling](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jvjwnb9675t0e38nd8rq.png)

### Profile <a name="profile"></a>

Now that we have registration and login set up, let’s create a route to set a name and avatar for users.

The Firebase [user](https://firebase.google.com/docs/reference/js/v8/firebase.User) object has basic properties such as `displayName`, `photoURL`, `phoneNumber`, etc. You can check this by logging the `currentUser` object on the console. We are going to update the user’s [profile](https://firebase.google.com/docs/auth/web/manage-users#update_a_users_profile) by using the `updateProfile` function from Firebase.

Open `AuthContext.js` and import this function:

```jsx
import { updateProfile } from "firebase/auth";
```

Add the following function alongside `register` and `login`

```jsx
function updateUserProfile(user, profile) {
    return updateProfile(user, profile);
}
```

- The `updateProfile` function takes a user and any user information we need to update.

Add `updateUserProfile` in `value` props.

```jsx
const value = {
    // ...
    updateUserProfile,
  };
```

We are going to update the display name and photo of the user. To generate cool avatars, we are going to use this [API](https://avatars.dicebear.com/docs/http-api).

- DiceBear uses the following URL as a source to generate images. [https://avatars.dicebear.com/api/:sprites/:seed.svg](https://avatars.dicebear.com/api/:sprites/:seed.svg)

> You can replace `:sprites` with `male`, `female`, `human`, `identicon`, `initials`, `bottts`,  `avataaars`, `jdenticon`, `gridy`or `micah`. The value of `:seed` can be anything you like but **don't** use any sensitive or personal data here!
> 

Inside the `src` folder, create a folder called `utils`. And inside it, create a file called `GenerateAvatar.js`

```jsx
// GenerateAvatar.js

const generateDiceBearAvataaars = (seed) =>
  `https://avatars.dicebear.com/api/avataaars/${seed}.svg`;

const generateDiceBearBottts = (seed) =>
  `https://avatars.dicebear.com/api/bottts/${seed}.svg`;

const generateDiceBearGridy = (seed) =>
  `https://avatars.dicebear.com/api/gridy/${seed}.svg`;

export const generateAvatar = () => {
  const data = [];

  for (let i = 0; i < 2; i++) {
    const res = generateDiceBearAvataaars(Math.random());
    data.push(res);
  }
  for (let i = 0; i < 2; i++) {
    const res = generateDiceBearBottts(Math.random());
    data.push(res);
  }
  for (let i = 0; i < 2; i++) {
    const res = generateDiceBearGridy(Math.random());
    data.push(res);
  }
  return data;
};
```

- The above function generates 6 random avatars and returns the array. We have exported the function so that we can use it elsewhere.

Now, create a file called `Profile.js` inside `accounts`. Most of the things in this file are going to be similar to `Register.js` and `Login.js`.

```jsx
// Profile.js

import { generateAvatar } from "../../utils/GenerateAvatar";

const [avatars, setAvatars] = useState([]);

useEffect(() => {
    const fetchData = () => {
      const res = generateAvatar();
      setAvatars(res);
    };

    fetchData();
  }, []);
```

- This will generate avatars using the utility function we created earlier and set them to the `avatars` state when the component mounts.

We will also have the following state to track the selected avatar.

```jsx
const [selectedAvatar, setSelectedAvatar] = useState();
```

This is what `Profile.js` looks like now

```jsx
// Profile.js

import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";

import { useAuth } from "../../contexts/AuthContext";
import { generateAvatar } from "../../utils/GenerateAvatar";

function classNames(...classes) {
  return classes.filter(Boolean).join(" ");
}

export default function Profile() {
  const navigate = useNavigate();

  const [username, setUsername] = useState("");
  const [avatars, setAvatars] = useState([]);
  const [selectedAvatar, setSelectedAvatar] = useState();
  const [loading, setLoading] = useState(false);

  const { currentUser, updateUserProfile, setError } = useAuth();

  useEffect(() => {
    const fetchData = () => {
      const res = generateAvatar();
      setAvatars(res);
    };

    fetchData();
  }, []);

  const handleFormSubmit = async (e) => {
    e.preventDefault();

    if (selectedAvatar === undefined) {
      return setError("Please select an avatar");
    }

    try {
      setError("");
      setLoading(true);
      const user = currentUser;
      const profile = {
        displayName: username,
        photoURL: avatars[selectedAvatar],
      };
      await updateUserProfile(user, profile);
      navigate("/");
    } catch (e) {
      setError("Failed to update profile");
    }

    setLoading(false);
  };

  return (
    <div className="min-h-full flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
      <div className="max-w-md w-full space-y-8">
        <div className="text-center">
          <h2 className="mt-4 text-3xl text-center tracking-tight font-light dark:text-white">
            Pick an avatar
          </h2>
        </div>
        <form className="space-y-6" onSubmit={handleFormSubmit}>
          <div className="flex flex-wrap -m-1 md:-m-2">
            {avatars.map((avatar, index) => (
              <div key={index} className="flex flex-wrap w-1/3">
                <div className="w-full p-1 md:p-2">
                  <img
                    alt="gallery"
                    className={classNames(
                      index === selectedAvatar
                        ? "border-4  border-blue-700 dark:border-blue-700"
                        : "cursor-pointer hover:border-4 hover:border-blue-700",
                      "block object-cover object-center w-36 h-36 rounded-full"
                    )}
                    src={avatar}
                    onClick={() => setSelectedAvatar(index)}
                  />
                </div>
              </div>
            ))}
          </div>

          <div className="rounded-md shadow-sm -space-y-px">
            <input
              id="username"
              name="username"
              type="text"
              autoComplete="username"
              required
              className="appearance-none rounded-none relative block w-full px-3 py-2 placeholder-gray-500 rounded-t-md bg-gray-50 border border-gray-300 text-gray-900 text-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 focus:z-10 sm:text-sm"
              placeholder="Enter a Display Name"
              defaultValue={currentUser.displayName && currentUser.displayName}
              onChange={(e) => setUsername(e.target.value)}
            />
          </div>
          <div>
            <button
              type="submit"
              disabled={loading}
              className="w-full py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
            >
              Update Profile
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}
```

Now, let’s create the route in `App.js`

```jsx
import Profile from "./components/accounts/Profile"; // Add this to the imports list

<Route exact path="/profile" element={<Profile />} /> // Add this route
```

Finally, go to [http://localhost:3000/profile](http://localhost:3002/profile) and check if everything is working. You will get something like this.


![Profile page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x47l7vy1mnu871l6uxtw.png)

When you update the profile, it will redirect you to a blank page, don’t worry we haven’t created a home page yet.

### Logout <a name="logout"></a>

First, let’s add the Firebase function that will allow us to [log out](https://firebase.google.com/docs/auth/web/password-auth#next_steps) users. Inside your `AuthContext.js`, add the following

```jsx
import { signOut } from "firebase/auth"; // Add this import

function logout() {
    return signOut(auth);
}
```

Simple as that! 

Then create a file called `Logout.js` inside the `accounts` folder. We are going to create a modal that will ask for the user’s confirmation to log out and fires the `logout` function. We are going to use the `Dialog` and `Transition` components from [Headless UI](https://headlessui.com/) so let’s install it first

```shell
npm i @headlessui/react
```

```jsx
// Logout.js

import { Fragment, useRef } from "react";
import { useNavigate } from "react-router-dom";
import { Dialog, Transition } from "@headlessui/react";
import { ExclamationIcon } from "@heroicons/react/outline";

import { useAuth } from "../../contexts/AuthContext";

export default function Logout({ modal, setModal }) {
  const cancelButtonRef = useRef(null);
  const navigate = useNavigate();

  const { logout, setError } = useAuth();

  async function handleLogout() {
    try {
      setError("");
      await logout();
      setModal(false);
      navigate("/login");
    } catch {
      setError("Failed to logout");
    }
  }

  return (
    <Transition.Root show={modal} as={Fragment}>
      <Dialog
        as="div"
        className="fixed z-10 inset-0 overflow-y-auto"
        initialFocus={cancelButtonRef}
        onClose={setModal}
      >
        <div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
          <Transition.Child
            as={Fragment}
            enter="ease-out duration-300"
            enterFrom="opacity-0"
            enterTo="opacity-100"
            leave="ease-in duration-200"
            leaveFrom="opacity-100"
            leaveTo="opacity-0"
          >
            <Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
          </Transition.Child>

          {/* This element is to trick the browser into centering the modal contents. */}
          <span
            className="hidden sm:inline-block sm:align-middle sm:h-screen"
            aria-hidden="true"
          >
            &#8203;
          </span>
          <Transition.Child
            as={Fragment}
            enter="ease-out duration-300"
            enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
            enterTo="opacity-100 translate-y-0 sm:scale-100"
            leave="ease-in duration-200"
            leaveFrom="opacity-100 translate-y-0 sm:scale-100"
            leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
          >
            <div className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
              <div className="bg-white dark:bg-gray-700 px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
                <div className="sm:flex sm:items-start">
                  <div className="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 dark:bg-gray-200 sm:mx-0 sm:h-10 sm:w-10">
                    <ExclamationIcon
                      className="h-6 w-6 text-red-600"
                      aria-hidden="true"
                    />
                  </div>
                  <div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
                    <Dialog.Title
                      as="h3"
                      className="text-lg leading-6 font-medium text-gray-500 dark:text-gray-400"
                    >
                      Logging out
                    </Dialog.Title>
                    <div className="mt-2">
                      <p className="text-sm text-gray-500 dark:text-gray-400">
                        Are you sure you want to log out ?
                      </p>
                    </div>
                  </div>
                </div>
              </div>
              <div className="bg-gray-50 dark:bg-gray-700 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
                <button
                  type="button"
                  className="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"
                  onClick={handleLogout}
                >
                  Logout
                </button>
                <button
                  type="button"
                  className="mt-3 w-full inline-flex justify-center shadow-sm px-4 py-2  sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm
                  rounded-md border border-gray-300 bg-white text-gray-500 text-base font-medium hover:bg-gray-100 focus:outline-none focus:ring-gray-200 focus:ring-2 focus:ring-offset-2 hover:text-gray-900 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-500 dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-gray-600
                  "
                  onClick={() => setModal(false)}
                  ref={cancelButtonRef}
                >
                  Cancel
                </button>
              </div>
            </div>
          </Transition.Child>
        </div>
      </Dialog>
    </Transition.Root>
  );
}
```

Done!

## Enable Dark Mode <a name="darkmode"></a>

If you have been paying attention to the Tailwind classes of our component elements, you must have seen something like `dark:text-white` This kind of style pattern is applied to the elements when dark mode is enabled. We haven’t enabled it yet, so let’s do that now.

Open your `tailwind.config.js` file and add the following:

```jsx
darkMode: "class",
```

Inside `layouts`, create a file called  `ThemeToggler.js` and add a button that will toggle between light and dark mode.

```jsx
// ThemeToggler.js

export default function ThemeToggler() {
  return (
    <button
      ref={themeToggleBtn}
      type="button"
      className="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none rounded-lg text-sm p-2.5"
      onClick={() => handleThemeToggle()}
    >
      <svg
        ref={themeToggleDarkIcon}
        className="hidden w-8 h-8"
        fill="currentColor"
        viewBox="0 0 20 20"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
      </svg>
      <svg
        ref={themeToggleLightIcon}
        className="hidden w-8 h-8"
        fill="currentColor"
        viewBox="0 0 20 20"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path
          d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
          fillRule="evenodd"
          clipRule="evenodd"
        ></path>
      </svg>
    </button>
  );
}
```

Create a `useRef` hook to access the above theme toggle button, theme toggle light icon, and theme toggle dark icon.

```jsx
import { useRef } from "react";

const themeToggleBtn = useRef();
const themeToggleLightIcon = useRef();
const themeToggleDarkIcon = useRef();
```

Add `refs` to the toggle button, dark icon, and light icon SVGs respectively like this:

```
ref={themeToggleBtn}
ref={themeToggleDarkIcon}
ref={themeToggleLightIcon}
```

For the button, add an `onClick` event listener:

```
onClick={() => handleThemeToggle()}
```

Let’s now create this function. When the button is pressed it will check whether or not the user has a color-theme set in local storage previously, add/remove the dark class, and update local storage.

```jsx
const handleThemeToggle = () => {
    themeToggleDarkIcon.current.classList.toggle("hidden");
    themeToggleLightIcon.current.classList.toggle("hidden");

    if (localStorage.getItem("color-theme")) {
      if (localStorage.getItem("color-theme") === "light") {
        document.documentElement.classList.add("dark");
        localStorage.setItem("color-theme", "dark");
      } else {
        document.documentElement.classList.remove("dark");
        localStorage.setItem("color-theme", "light");
      }
    } else {
      if (document.documentElement.classList.contains("dark")) {
        document.documentElement.classList.remove("dark");
        localStorage.setItem("color-theme", "light");
      } else {
        document.documentElement.classList.add("dark");
        localStorage.setItem("color-theme", "dark");
      }
    }
  };
```

Next, when the component renders, we want to either set the dark or light mode by checking previous user preference or settings.

```jsx
useEffect(() => {
    if (
      localStorage.getItem("color-theme") === "dark" ||
      (!("color-theme" in localStorage) &&
        window.matchMedia("(prefers-color-scheme: dark)").matches)
    ) {
      document.documentElement.classList.add("dark");
      themeToggleLightIcon.current.classList.remove("hidden");
    } else {
      document.documentElement.classList.remove("dark");
      themeToggleDarkIcon.current.classList.remove("hidden");
    }
  }, []);
```

Final code for `ThemeToggler.js`

```jsx
// ThemeToggler.js

import { useEffect, useRef } from "react";

export default function ThemeToggler() {
  const themeToggleBtn = useRef();
  const themeToggleLightIcon = useRef();
  const themeToggleDarkIcon = useRef();

  useEffect(() => {
    if (
      localStorage.getItem("color-theme") === "dark" ||
      (!("color-theme" in localStorage) &&
        window.matchMedia("(prefers-color-scheme: dark)").matches)
    ) {
      document.documentElement.classList.add("dark");
      themeToggleLightIcon.current.classList.remove("hidden");
    } else {
      document.documentElement.classList.remove("dark");
      themeToggleDarkIcon.current.classList.remove("hidden");
    }
  }, []);

  const handleThemeToggle = () => {
    themeToggleDarkIcon.current.classList.toggle("hidden");
    themeToggleLightIcon.current.classList.toggle("hidden");

    if (localStorage.getItem("color-theme")) {
      if (localStorage.getItem("color-theme") === "light") {
        document.documentElement.classList.add("dark");
        localStorage.setItem("color-theme", "dark");
      } else {
        document.documentElement.classList.remove("dark");
        localStorage.setItem("color-theme", "light");
      }
    } else {
      if (document.documentElement.classList.contains("dark")) {
        document.documentElement.classList.remove("dark");
        localStorage.setItem("color-theme", "light");
      } else {
        document.documentElement.classList.add("dark");
        localStorage.setItem("color-theme", "dark");
      }
    }
  };

  return (
    <button
      ref={themeToggleBtn}
      type="button"
      className="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none rounded-lg text-sm p-2.5"
      onClick={() => handleThemeToggle()}
    >
      <svg
        ref={themeToggleDarkIcon}
        className="hidden w-8 h-8"
        fill="currentColor"
        viewBox="0 0 20 20"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
      </svg>
      <svg
        ref={themeToggleLightIcon}
        className="hidden w-8 h-8"
        fill="currentColor"
        viewBox="0 0 20 20"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path
          d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
          fillRule="evenodd"
          clipRule="evenodd"
        ></path>
      </svg>
    </button>
  );
}
```

Finally, to apply dark mode to the body of our application, add the following in `index.css`. It will add our own default base styles for the body.

```css
@layer base {
    body {
      @apply bg-white dark:bg-gray-900;
    }
  }
```

Let’s quickly add a navigation component and we will test the logout and dark mode functionalities.

## Navigation <a name="navigation"></a>

The navigation will contain theme toggler, logout and profile icons.

Inside `layouts` create a file called `Header.js`

```jsx
// Header.js

import { LogoutIcon } from "@heroicons/react/outline";
import { useState } from "react";
import { Link } from "react-router-dom";

import { useAuth } from "../../contexts/AuthContext";
import Logout from "../accounts/Logout";
import ThemeToggler from "./ThemeToggler";

export default function Header() {
  const [modal, setModal] = useState(false);

  const { currentUser } = useAuth();

  return (
    <>
      <nav className="px- px-2 sm:px-4 py-2.5 bg-gray-50 border-gray-200 dark:bg-gray-800 dark:border-gray-700 text-gray-900 text-sm rounded border dark:text-white">
        <div className="container mx-auto flex flex-wrap items-center justify-between">
          <Link to="/" className="flex">
            <span className="self-center text-lg font-semibold whitespace-nowrap text-gray-900 dark:text-white">
              Chat App
            </span>
          </Link>
          <div className="flex md:order-2">
            <ThemeToggler />

            {currentUser && (
              <>
                <button
                  className="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none rounded-lg text-sm p-2.5"
                  onClick={() => setModal(true)}
                >
                  <LogoutIcon className="h-8 w-8" aria-hidden="true" />
                </button>

                <Link
                  to="/profile"
                  className="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none rounded-full text-sm p-2.5"
                >
                  <img
                    className="h-8 w-8 rounded-full"
                    src={currentUser.photoURL}
                    alt=""
                  />
                </Link>
              </>
            )}
          </div>
        </div>
      </nav>
      {modal && <Logout modal={modal} setModal={setModal} />}
    </>
  );
}
```

- We used conditional rendering to display the logout and profile icons only when the user is authenticated.
- The modal state will be used to render the `Logout` modal for confirmation.

Finally, let’s render `Header.js` inside `App.js`

```jsx
// App.js

import Header from "./components/layouts/Header"; // Add this

<AuthProvider>
    <Router>
      <Header /> // And this
      <ErrorMessage />
      <Routes>
        <Route exact path="/register" element={<Register />} />
        <Route exact path="/login" element={<Login />} />
        <Route exact path="/profile" element={<Profile />} />
      </Routes>
    </Router>
</AuthProvider>
```

To test this go to [http://localhost:3000/profile](http://localhost:3000/profile). You will get something like this when dark mode is enabled.


![Dark mode Profile page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hkuuixt209k46x8y4xaz.png)

The logout modal (with light mode):


![Logout modal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vrh4wr35vq60d66hid7w.png)

Great! moving on to private routes.

## Private Route <a name="proute"></a>

Routes such as `/profile` should only be accessed if the user is logged in. To make such components private, let’s go ahead and create a higher-order component that will wrap them.

Inside the `utils` folder, create a file called `WithPrivateRoute.js`

```jsx
// WithPrivateRoute.js

import { Navigate } from "react-router-dom";
import { useAuth } from "../contexts/AuthContext";

const WithPrivateRoute = ({ children }) => {
  const { currentUser } = useAuth();

	// If there is a current user it will render the passed down component
  if (currentUser) {
    return children;
  }
	
  // Otherwise redirect to the login route
  return <Navigate to="/login" />;
};

export default WithPrivateRoute;
```

We can now use this higher-order component to wrap `Profile.js`

The final look of `App.js`:

```jsx

// App.js

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";

import { AuthProvider } from "./contexts/AuthContext";
import Register from "./components/accounts/Register";
import Login from "./components/accounts/Login";
import Profile from "./components/accounts/Profile";
import WithPrivateRoute from "./utils/WithPrivateRoute";
import Header from "./components/layouts/Header";
import ErrorMessage from "./components/layouts/ErrorMessage";

function App() {
  return (
    <AuthProvider>
      <Router>
        <Header />
        <ErrorMessage />
        <Routes>
          <Route exact path="/register" element={<Register />} />
          <Route exact path="/login" element={<Login />} />
          <Route
            exact
            path="/profile"
            element={
              <WithPrivateRoute>
                <Profile />
              </WithPrivateRoute>
            }
          />
        </Routes>
      </Router>
    </AuthProvider>
  );
}

export default App;
```

You can test this by trying to access the profile page without logging in.

This marks the end of the frontend section for authentication. Let’s now get started with Express to verify users for subsequent requests.

---

## Express Server <a name="express"></a>

### Express Boilerplate <a name="boilerplate"></a>

The backend is going to be an independent app, so in a new terminal type in the following:

```shell
npm init -y
```

This will create a `package.json` file 


![Express package.json](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w79wrtb1c01vzut3c1jv.png)

Open it up and let’s modify a couple of things.

First, we are going to use ES 6 modules (import syntax), so let’s enable it.

```jsx
"type": "module",
```

We are also going to use [nodemon](https://www.npmjs.com/package/nodemon) so that we don’t need to restart our server every time we make changes. If you haven’t already, install it globally:

```shell
npm install -g nodemon
```

Then add the following to the scripts (we will create `server/index.js` next)

```jsx
"start": "nodemon server/index.js"
```

Your `package.json` should look like this

```jsx
{
  "name": "chat-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon server/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.18.1"
  }
}
```

Now install Express:

```shell
npm i express
```

Create a folder named `server`, `cd` into it, and create `index.js` file. This is where we will set up our server.

```shell
mkdir server
cd server
touch index.js
```

Inside `index.js` let’s add a simple endpoint to fire up and test our server.

```jsx
// index.js

import express from "express";

const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.get("/", (req, res) => {
  res.send("working fine");
});

const PORT = 3001;

app.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
});
```

To test it:

```shell
cd ../
npm start
```

Now, if you go to [http://localhost:3001/](http://localhost:3001/) on your browser, you should see the **“working fine”** output.

### Enabling Cors <a name="cors"></a>

We need to enable [cors](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) to allow React to send requests to Express.

Install cors:

```shell
npm i cors
```

And inside `index.js`

```jsx
import cors from "cors"; // Add this to the list of imports

app.use(cors()); // Use the cors middleware
```

### Using Environment Variables <a name="env"></a>

To use environment variables, let’s install [dotenv](https://www.npmjs.com/package/dotenv)

```shell
npm i dotnev
```

Then create a `.env` file at the root of your project

```jsx
touch .env
```

Open it and add the port

```jsx
PORT=3001
```

Then in `index.js` import `dotenv` and access the `PORT` variable we just created.

```jsx
import dotenv from "dotenv"; // Add to import list

dotenv.config(); // Configure dotenv to access the env variables

const PORT = process.env.PORT || 8080; // Use this instead of hardcoding it like before
```

## Connect with React <a name="express-react"></a>

Now that we have enabled `cors`, let’s test this by sending a request from React.

Go to the `frontend` folder and open up `Header.js` from `components/layouts`. Add the following `useEffect` hook. Note that this is just for testing purposes. You can get rid of it later.

```jsx
useEffect(() => {
    const fetchData = async () => {
      try {
        const res = await fetch("http://localhost:3001");
        console.log(await res.text());
      } catch (e) {
        console.log(e);
      }
    };

    fetchData();
  }, []);
```

- We are making a request to this [http://localhost:3001](http://localhost:3001) endpoint using the built-in `fetch` API and logging the response to the console. If you head over to your React app at [http://localhost:3000/](http://localhost:3000/), you should see the **“working fine”** output in the console.

Dope! React can communicate with the backend now. However, what we want to do is prevent React from getting a response if a verified user token is not sent. We will do 2 things:

1. [Send the Firebase token from the frontend to the backend](#token)
2. [Create a middleware in Express to verify the token](#middleware)

### Sending Firebase Token to Express <a name="token"></a>

Again, open `Header.js`, and let’s modify the previous request to send the authentication token as a header `Authorization: Bearer token`. *How can we get the token?* Firebase makes this really easy.

```jsx
// Header.js

import auth from "../../config/firebase";

useEffect(() => {
    const fetchData = async () => {
      try {
        const user = auth.currentUser;
        const token = user && (await user.getIdToken());

        const payloadHeader = {
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${token}`,
          },
        };
        const res = await fetch("http://localhost:3001", payloadHeader);
        console.log(await res.text());
      } catch (e) {
        console.log(e);
      }
    };

    fetchData();
}, []);
```

- First, we imported `auth` from our firebase config. We can use this to get the current user instance. `getIdToken()` returns the token if it has not expired or if it will not expire in the next five minutes. Otherwise, this will refresh the token and return a new one.

Now if you go to [http://localhost:3000/](http://localhost:3000/) **network tab**, you can see the `Authorization` header being sent as well.

This is looking good. The next step is to verify the token in our backend.

### Creating the Middleware <a name="middleware"></a>

The middleware we are going to create will access the request to find the token. Then, we will verify it. *How?* Again, Firebase to the rescue! Firebase has a backend [module](https://firebase.google.com/docs/auth/admin/verify-id-tokens) that allows us to verify the token. Let’s install it.

Inside your root directory (where `package.json` and `frontend` folder are located):

```shell
npm i firebase-admin
```

According to the [docs](https://firebase.google.com/docs/admin/setup) to use Firebase-admin SDK we need:

- [x]  A Firebase project.
- [x]  A Firebase Admin SDK service account to communicate with Firebase. This service account is created automatically when you create a Firebase project or add Firebase to a Google Cloud project.
- [ ]  A configuration file with your service account's credentials.

We have done the first 2. To get the service account go to your Firebase Dashboard and open Settings in the side panel. Then click the **Service Accounts** tab and click **Generate New Private Key**, then confirm by clicking **Generate Key**.

Once you download the `JSON` file containing the keys, go back to your project and navigate to the `server` folder. Create a folder called `config` and inside it, create a file called `serviceAccountKey.json`. This is where we will put the generated keys.

```shell
cd server
mkdir config
cd config
touch serviceAccountKey.json
```

After copy-pasting the keys into this file, create another file inside this `config` folder called `firebase-config.js`

```jsx
touch firebase-config.js
```

Then open this file and,

```jsx
//firebase-config.js

import { initializeApp, cert } from "firebase-admin/app";
import { getAuth } from "firebase-admin/auth";

import serviceAccountKey from "./serviceAccountKey.json" assert { type: "json" };

const app = initializeApp({
  credential: cert(serviceAccountKey),
});

const auth = getAuth(app);
export default auth;
```

- We imported the `JSON` file with the Firebase configurations and used it to initialize the Firebase SDK. We then exported `auth` to use it elsewhere.

Next, inside the `server` folder, create a folder called `middleware`. Inside `middleware`, create a file called `VerifyToken.js`


![Folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2sru9dyo3c6gh6prqgjw.png)

Then, open `VerifyToken.js` and add the following:

```jsx
// VerifyToken.js

import auth from "../config/firebase-config.js";

export const VerifyToken = async (req, res, next) => {
  const token = req.headers.authorization.split(" ")[1];

  try {
    const decodeValue = await auth.verifyIdToken(token);
    if (decodeValue) {
      req.user = decodeValue;
      return next();
    }
  } catch (e) {
    return res.json({ message: "Internal Error" });
  }
};
```

- First, we imported the Firebase `auth` we created earlier.
- `const token = req.headers.authorization.split(" ")[1];` Here we are splitting the authorization header to get the token from the request.
- `auth.verifyIdToken(token);` will decode the token to its associated user. Finally, we check if this decoded value is the same as the user sending the request.

Let’s now use this `middleware` in `index.js`

```jsx

import { VerifyToken } from "./middlewares/VerifyToken.js";

app.use(VerifyToken); // Add this middleware
```

`index.js` will look like this:

```jsx
// index.js

import express from "express";
import cors from "cors";
import dotenv from "dotenv";

import { VerifyToken } from "./middlewares/VerifyToken.js";

const app = express();

dotenv.config();

app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.use(VerifyToken);

const PORT = process.env.PORT || 8080;

app.get("/", (req, res) => {
  res.send("working fine");
});

app.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
});
```

Now, if you go back to [http://localhost:3000/](http://localhost:3000/) and refresh, you will see **“working fine”** outputted on the console. However, if you replace the token with some random value or remove the header, Express will reject the request.

**Perfect!** Everything is working now.

---

## Final Thoughts <a name="final"></a>

*Got lost somewhere throughout the process?* No problem, check out the project on [GitHub](https://github.com/earthcomfy/lets-chat) or ask your question in the comments section.

*Feedback or comment?* let me know down below. Thanks!