# Implement Email/Password Authentication in React

> **Note:** GraphQL is deprecated. Learn more.

Welcome back to our journey building a full stack web application with MongoDB Atlas App Services, GraphQL, and React!

In the first part of the series, we configured the email/password authentication provider in our backend App Service. In this second article, we will integrate the authentication into a web application built with React. We will write only a single line of server-side code and let the App Service handle the rest!

We will also build the front end of our expense management application, Expengo, using React. By the end of today’s tutorial, we will have the following web application:

## Set up your React web application

Make sure you have Node.js and npm installed on your machine. You can check if they’re correctly set up by running the following commands in your terminal emulator:

```sh
node -v
npm -v
```

### Create the React app
Let’s create a brand new React app. Launch your terminal and execute the following command, where “expengo” will be the name of our app:

```sh
npx create-react-app expengo -y
```

The process may take up to a minute to complete. After it’s finished, navigate to your new project:

```sh
cd expengo
```

### Add required dependencies
Next, we’ll install the Realm Web SDK. The SDK enables browser-based applications to access data stored in MongoDB Atlas and interact with Atlas App Services like Functions, authentication, and GraphQL.

```
npm install realm-web
```

We’ll also install a few other npm packages to make our lives easier:

1. React-router-dom to manage navigation in our app:

    ```
    npm install react-router-dom
    ```
   
1. Material UI to help us build beautiful components without writing a lot of CSS:

    ```
    npm install @mui/material @emotion/styled @emotion/react
    ```

### Scaffold the application structure
Finally, let’s create three new directories with a few files in them. To do that, we’ll use the shell. Feel free to use a GUI or your code editor if you prefer.

```sh
(cd src/ && mkdir pages/ contexts/ realm/)
(cd src/pages && touch Home.page.js PrivateRoute.page.js Login.page.js Signup.page.js)
(cd src/contexts && touch user.context.js)
(cd src/realm && touch constants.js)
```

Open the expengo directory in your code editor. The project directory should have the following structure:

```
├── README.md
└──node_modules/
├── …
├── package-lock.json
├── package.json
└── public/
 ├── …
└──src/
 └──contexts/
  ├──user.context.js
 └──pages/
  ├──Home.page.js
  ├──PrivateRoute.page.js
  ├──Login.page.js
  ├──Signup.page.js
 └── realm/
  ├──constants.js
 ├── App.css
 ├── App.js
 ├── App.test.js
 ├── index.css
 ├── index.js
 ├── logo.svg
 ├── reportWebVitals.js
 └── setupTests.js
```

## Connect your React app with App Services and handle user management

In this section, we will be creating functions and React components in our app to give our users the ability to log in, sign up, and log out.

* Start by copying your App Services App ID:

Now open this file: `./src/realm/constants.js`

Paste the following code and replace the placeholder with your app Id:

```js
export const APP_ID = "<-- Your App ID -->";
```

### Create a React Context for user management
Now we will add a new React Context on top of all our routes to get access to our user’s details, such as their profile and access tokens. Whenever we need to call a function on a user’s behalf, we can easily do that by consuming this React Context through child components.
The following code also implements functions that will do all the interactions with our Realm Server to perform authentication. Please take a look at the comments for a function-specific description.

**./src/contexts/user.context.js**

```js
import { createContext, useState } from "react";
import { App, Credentials } from "realm-web";
import { APP_ID } from "../realm/constants";
 
// Creating a Realm App Instance
const app = new App(APP_ID);
 
// Creating a user context to manage and access all the user related functions
// across different components and pages.
export const UserContext = createContext();
 
export const UserProvider = ({ children }) => {
 const user, setUser] = useState(null);
 
 // Function to log in user into our App Service app using their email & password
 const emailPasswordLogin = async (email, password) => {
   const credentials = Credentials.emailPassword(email, password);
   const authenticatedUser = await app.logIn(credentials);
   setUser(authenticatedUser);
   return authenticatedUser;
 };
 
 // Function to sign up user into our App Service app using their email & password
 const emailPasswordSignup = async (email, password) => {
   try {
     await app.emailPasswordAuth.registerUser(email, password);
     // Since we are automatically confirming our users, we are going to log in
     // the user using the same credentials once the signup is complete.
     return emailPasswordLogin(email, password);
   } catch (error) {
     throw error;
   }
 };
 
 // Function to fetch the user (if the user is already logged in) from local storage
 const fetchUser = async () => {
   if (!app.currentUser) return false;
   try {
     await app.currentUser.refreshCustomData();
     // Now, if we have a user, we are setting it to our user context
     // so that we can use it in our app across different components.
     setUser(app.currentUser);
     return app.currentUser;
   } catch (error) {
     throw error;
   }
 }
 
 // Function to logout user from our App Services app
 const logOutUser = async () => {
   if (!app.currentUser) return false;
   try {
     await app.currentUser.logOut();
     // Setting the user to null once loggedOut.
     setUser(null);
     return true;
   } catch (error) {
     throw error
   }
 }
 
 return 
   {children}
 ;
}
```

## Create a PrivateRoute page
This is a wrapper page that will only allow authenticated users to access our app’s private pages. We will see it in action in our ./src/App.js file.

**./src/pages/PrivateRoute.page.js**

```js
import { useContext } from "react";
import { Navigate, Outlet, useLocation } from "react-router-dom";
import { UserContext } from "../contexts/user.context";
 
const PrivateRoute = () => {
 
 // Fetching the user from the user context.
 const { user } = useContext(UserContext);
 const location = useLocation();
 const redirectLoginUrl = `/login?redirectTo=${encodeURI(location.pathname)}`;
 
 // If the user is not logged in we are redirecting them
 // to the login page. Otherwise we are letting them to
 // continue to the page as per the URL using .
 return !user ?  :  ;
}
 
export default PrivateRoute;
```

## Create a login page
Next, let’s add a login page.

**./src/pages/Login.page.js**

```js
import { Button, TextField } from "@mui/material";
import { useContext, useEffect, useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { UserContext } from "../contexts/user.context";
 
const Login = () => {
 const navigate = useNavigate();
 const location = useLocation();
 
 // We are consuming our user-management context to
 // get & set the user details here
 const { user, fetchUser, emailPasswordLogin } = useContext(UserContext);
 
 // We are using React's "useState" hook to keep track
 //  of the form values.
 const [form, setForm] = useState({
   email: "",
   password: ""
 });
 
 // This function will be called whenever the user edits the form.
 const onFormInputChange = (event) => {
   const { name, value } = event.target;
   setForm({ ...form, [name]: value });
 };
 
 // This function will redirect the user to the
 // appropriate page once the authentication is done.
 const redirectNow = () => {
   const redirectTo = location.search.replace("?redirectTo=", "");
   navigate(redirectTo ? redirectTo : "/");
 }
 
 // Once a user logs in to our app, we don’t want to ask them for their
 // credentials again every time the user refreshes or revisits our app, 
 // so we are checking if the user is already logged in and
 // if so we are redirecting the user to the home page.
 // Otherwise we will do nothing and let the user to login.
 const loadUser = async () => {
   if (!user) {
     const fetchedUser = await fetchUser();
     if (fetchedUser) {
       // Redirecting them once fetched.
       redirectNow();
     }
   }
 }
 
 // This useEffect will run only once when the component is mounted.
 // Hence this is helping us in verifying whether the user is already logged in
 // or not.
 useEffect(() => {
   loadUser(); // eslint-disable-next-line react-hooks/exhaustive-deps
 }, []);
 
 // This function gets fired when the user clicks on the "Login" button.
 const onSubmit = async (event) => {
   try {
     // Here we are passing user details to our emailPasswordLogin
     // function that we imported from our realm/authentication.js
     // to validate the user credentials and log in the user into our App.
     const user = await emailPasswordLogin(form.email, form.password);
     if (user) {
       redirectNow();
     }
   } catch (error) {
       if (error.statusCode === 401) {
          alert("Invalid username/password. Try again!");
      } else {
          alert(error);
      }
 
   }
 };
 
 return 
   

LOGIN

   
   
   
     Login
   
   

Don't have an account? Signup

 
}
 
export default Login;
```

## Create a signup page
Now our users can log into the application, but how do they sign up? Time to add a signup page!

**./src/pages/Signup.page.js**

```js
import { Button, TextField } from "@mui/material";
import { useContext, useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { UserContext } from "../contexts/user.context";
 
const Signup = () => {
 const navigate = useNavigate();
 const location = useLocation();
 
 // As explained in the Login page.
 const { emailPasswordSignup } = useContext(UserContext);
 const [form, setForm] = useState({
   email: "",
   password: ""
 });
 
 // As explained in the Login page.
 const onFormInputChange = (event) => {
   const { name, value } = event.target;
   setForm({ ...form, [name]: value });
 };
 
 
 // As explained in the Login page.
 const redirectNow = () => {
   const redirectTo = location.search.replace("?redirectTo=", "");
   navigate(redirectTo ? redirectTo : "/");
 }
 
 // As explained in the Login page.
 const onSubmit = async () => {
   try {
     const user = await emailPasswordSignup(form.email, form.password);
     if (user) {
       redirectNow();
     }
   } catch (error) {
     alert(error);
   }
 };
 
 return 
   

SIGNUP

   
   
   
     Signup
   
   

Have an account already? Login

 
}
 
export default Signup;
```

## Create a homepage
Our homepage will be a basic page with a title and logout button.

**./src/pages/Home.page.js:**

```js
import { Button } from '@mui/material'
import { useContext } from 'react';
import { UserContext } from '../contexts/user.context';
 
export default function Home() {
 const { logOutUser } = useContext(UserContext);
 
 // This function is called when the user clicks the "Logout" button.
 const logOut = async () => {
   try {
     // Calling the logOutUser function from the user context.
     const loggedOut = await logOutUser();
     // Now we will refresh the page, and the user will be logged out and
     // redirected to the login page because of the  component.
     if (loggedOut) {
       window.location.reload(true);
     }
   } catch (error) {
     alert(error)
   }
 }
 
 return (
   <>
     

WELCOME TO EXPENGO

     Logout
   </>
 )
}
```

## Putting it all together in App.js
Let’s connect all of our pages in the root React component—App.

**./src/App.js**

```js
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { UserProvider } from "./contexts/user.context";
import Home from "./pages/Home.page";
import Login from "./pages/Login.page";
import PrivateRoute from "./pages/PrivateRoute.page";
import Signup from "./pages/Signup.page";
 
function App() {
 return (
   
     {/* We are wrapping our whole app with UserProvider so that */}
     {/* our user is accessible through out the app from any page*/}
     
       
         } />
         } />
         {/* We are protecting our Home Page from unauthenticated */}
         {/* users by wrapping it with PrivateRoute here. */}
         }>
           } />
         
       
     
   
 );
}
 
export default App;
```

## Launch your React app
All have to do now is run the following command from your project directory:

```
npm start
```

Once the compilation is complete, you will be able to access your app from your browser at http://localhost:3000/. You should be able to sign up and log into your app now.

## Conclusion
Woah! We have made a tremendous amount of progress. Authentication is a very crucial part of any app and once that’s done, we can focus on features that will make our users’ lives easier. In the next part of this blog series, we’ll be leveraging App Services GraphQL to perform CRUD operations. I’m excited about that because the basic setup is already over.

If you have any doubts or concerns, please feel free to reach out to us on the MongoDB Community Forums. I have created a [dedicated forum topic for this blog where we can discuss anything related to this blog series.

And before you ask, here’s the GitHub repository, as well!