React authentication with Firebase
Tags: react, redux, authentication, firebase
Published: 2021-10-21 18:21:43

---
title: React authentication with Firebase
published: true
description: Authententication in React with Firebase, using Redux Toolkit to store user data!
tags: react, redux, authentication, firebase
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bvlnqvksg63nnj42dy36.png
 
---

Hello everyone, in this guide I will show you how to set up basic authentication in React with Firebase. We will be also using react-router for creating routes (public and protected) and Redux ToolKit for saving user tokens to our applications state.

## Project setup

First, we need to install React 
`npx create-react-app react-firebase`
After it is installed we need to install dependencies we will use throughout this guide:
* React Router DOM: `npm install react-router-dom`
* Firebase: `npm install firebase`
* Redux and Redux Toolkit: `npm install react-redux` and `npm install @reduxjs/toolkit`

After everything is installed you can start the local server:
`cd react-firebase`
`npm start`
If everything is alright you will get this screen:

![React boilerplate start page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/goeit019dgcx4qiaqtj7.png)

## Project structure

In the src folder, we will create four new folders (configs, pages, redux, and utils). Configs will contain configuration for Firebase. Pages will contain all our pages, I also created a subfolder auth which will contain all pages regarding user authentication. Redux folder will container redux store and slices. Utils folder is for utilities like protected route components.
 
![Project structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2lskffzxhw5ezq6n0ehb.png)

## Creating pages and routes

In pages->auth we will create 3 pages: Register, Login, Reset (password reset). I also created a folder „protected“ which has a page for authenticated users and a Home page for every user.

![Pages folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s7vxwrawzw6d09fdxgy3.png)

### Login page
 
Below you can see basic React code for Login, it has two controlled inputs.

```javascript
import React, { useState } from "react";

const Login = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const handleLogin = () => {
    //here will go code for sign in
  };
  return (
    <div>
      <h1>Login</h1>
      Email:
      <br />
      <input
        type="text"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <br />
      Password:
      <br />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <br />
      <button onClick={handleLogin}>Log In</button>
    </div>
  );
};

export default Login;
```

### Register

```javascript
import React, { useState } from "react";

const Login = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const handleRegister = () => {
    //here will go code for sign up
  };
  return (
    <div>
      <h1>Register</h1>
      Email:
      <br />
      <input
        type="text"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <br />
      Password:
      <br />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <br />
      <button onClick={handleRegister}>Register</button>
    </div>
  );
};

export default Login;

```

### Password reset

```javascript
import React, { useState } from "react";

const Reset = () => {
  const [email, setEmail] = useState("");
  const handleReset = () => {
    //here will go code for password reset
  };
  return (
    <div>
      <h1>Reset password</h1>
      Email:
      <br />
      <input
        type="text"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <br />
      <button onClick={handleReset}>Reset password</button>
    </div>
  );
};

export default Reset;

```
The next step is to create links and routes for pages that will be in the App.js file. We can delete boilerplate code in App.js and write our own code.

```javascript
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import Login from "./pages/auth/Login";
import Register from "./pages/auth/Register";
import Reset from "./pages/auth/Reset";
import Home from "./pages/Home";
import Secret from "./pages/protected/Secret";

function App() {
  return (
    <Router>
      <nav>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/login">Login</Link>
          </li>
          <li>
            <Link to="/register">Register</Link>
          </li>
          <li>
            <Link to="/reset">Reset password</Link>
          </li>
          <li>
            <Link to="/protected">Protected page</Link>
          </li>
          <li>
            <Link to="#">Log out</Link>
          </li>
        </ul>
      </nav>

      <Switch>
        <Route exact path="/register">
          <Register />
        </Route>
        <Route exact path="/login">
          <Login />
        </Route>
        <Route exact path="/reset">
          <Reset />
        </Route>
        <Route exact path="/protected">
          <Secret />
        </Route>
        <Route exact path="/">
          <Home />
        </Route>
      </Switch>
    </Router>
  );
}

export default App;
```
First, we import react-router-dom dependencies and pages we just created. Then put `<Router>` as the root component. Under that is created basic navigation, instead of `<a>` element is used `<Link>` which doesn't refresh page on click (that's the point of Single Page Applications). Under navigation is a switch where we declare routes and components which they render. Now our screen looks something like this:

![New homepage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hvi6gw489sycb25rrjor.png)

The home page component is rendered at localhost:3000, if you click on the link in the navigation, other components will load without refreshing the page. Only Log Out doesn't render anything since it will be just used to log out.

## Setting up Firebase

First, you need to create a Firebase account at https://firebase.google.com/ and go to the Firebase console at https://console.firebase.google.com. Click on „Add project“ and follow three simple steps.

![Add project page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5lfwyd7l0s588kr6euwt.png)

After you finished with three steps you will be redirected to the screen which looks like on the picture below. Click on the </> icon to generate code for the web app.

![Get started with app -page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wl6wulcbb1uy3x1venjp.png)
 
Then enter the name of the app:

![Enter name of the app - page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ifbfjusym32zannkf9tk.png)

And then you get configuration for your app!

![App configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i72yh6ezjlctbz2ckuy1.png)
 
Now you can go to our project and in the config folder create file firebaseConfig.js. Paste config object and export it.

![firebaseConfig.js file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ht2btumkbm2z8pb8u6uw.png)

After creating the config it's time to initialize Firebase in our project, we do this in App.js. First, we need to import config from our file and initializeApp from firebase, then at the top of our component, we initialize it.

![App.js code snippet](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnbru5umrjnnl0k9ysir.png)
 
There is one last thing to do. We need to enable email and password authentication in the Firebase console. To do that go to your project, press on the „Authentication“ link on the left sidebar, then „Set up sign-in method“ in the middle of the screen. Click on email and password, enable it, and save.

![Firebase authentication page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1j5ifl0d9eqchspycwjj.png)

With this Firebase setup is finished. In the next part, we will integrate existing forms in our project with Firebase to actually register, login, and log out users, as well as send password reset links.

## Finish registration, login, log out and password reset

### Registration

To register a user we need to import getAuth and createUserWithEmailAndPassword from firebase. getAuth gets us an instance of initialized auth service.

```javascript
import { getAuth, createUserWithEmailAndPassword } from "firebase/auth";
```
Now we can declare variable auth which will hold auth service. Next, we can use „createUserWithEmailAndPassword“ in our handleRegister, first argument is auth service, then email, and lastly password. We create a promise if registration is successful you will get the user object logged in the console, if it wasn't successful, an error will be logged.

```javascript
const auth = getAuth();
  const handleRegister = () => {
    createUserWithEmailAndPassword(auth, email, password)
      .then((userCredential) => {
        const user = userCredential.user;
        console.log("Registered user: ", user);
        setEmail("");
        setPassword("");
      })
      .catch((error) => {
        const errorCode = error.code;
        const errorMessage = error.message;
        console.log("Error ocured: ", errorCode, errorMessage);
      });
  };

```
Here you can see the user object in the console after successful register:

![Successful register](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iebtlpzeg74no1d97jvu.png)
 
### Login

For the login page, we do the same, but this time we are using „signInWithEmailAndPassword“. Just like last time, import getAuth and this time signInWithEmailAndPassword. Here is a code snippet of signIn handler.

```javascript
const signIn = () => {
    signInWithEmailAndPassword(auth, email, password)
      .then((userCredential) => {
        const user = userCredential.user;
        console.log("Singed in user: ", user);
      })
      .catch((error) => {
        const errorCode = error.code;
        const errorMessage = error.message;
        console.log("An error occured: ", errorCode, errorMessage);
      });
  };
```

### Password reset

Repeat the steps for a password reset, but this time use sendPasswordResetEmail. This method only requires email. Here is a code snippet.

```javascript
const handleReset = () => {
    sendPasswordResetEmail(auth, email)
      .then(() => {
        console.log("success");
      })
      .catch((error) => {
        const errorCode = error.code;
        const errorMessage = error.message;
        console.log("An error has occured: ", errorCode, errorMessage);
      });
  };
```
If it's successful you will get an email which will send you to page like this:

![Firebase password reset](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5q2iv7bssyol3yac18hw.png)
 

### Log out

Since our navigation is directly in App.js, this is where we will implement log-out functionality. First import getAuth and signOut. Then add the following code to the „Log out“ link.

```javascript
<Link
  to="#"
  onClick={() => {
    signOut(auth)
      .then(() => {
        console.log("user signed out");
      })
      .catch((error) => {
        console.log("error", error);
      });
  }}
>
  Log out
</Link>
```

## Setting up Redux Toolkit

In redux->slices folder create file authSlice.js. This file will save user in a global state and there will also be defined methods to manipulate with the state. Here is a code snippet:

```javascript
import { createSlice } from "@reduxjs/toolkit";

const initialState = {};

export const authSlice = createSlice({
  name: "user",
  initialState,
  reducers: {
    saveUser: (state, action) => {
      state.value = action.payload;
    },
  },
});

// Action creators are generated for each case reducer function
export const { saveUser } = authSlice.actions;

export default authSlice.reducer;
```
First, we import createSlice from RTK. Then initialize state as an empty object, next we create authSlice which has the name „user“, it has an initial state which is the empty object, and one reducer „saveUser“. saveUser takes two arguments, the first is a state which this slice has and the second is the action that will trigger it. It sets the value of the state to the payload of action (what you pass as an argument to that action). Lastly, we export saveUser and authSlice.

The next step is to set up a store which will hold state. In the root of redux folder create store.js file.

```javascript
import { configureStore } from "@reduxjs/toolkit";
import authReducer from "./slice/authSlice";
export const store = configureStore({
  reducer: {
    auth: authReducer,
  },
});
```
Here we configure the store with one auth reducer. This is how your redux folder structure should look like now:

![redux folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kdybohmpkfkj57i0167x.png)
 
Now we need to provide a state from Redux to our app, to do that we need to wrap our <App /> component in index.js with the provider from redux which will use our store configuration.

```javascript
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import { store } from "./redux/store";
import { Provider } from "react-redux";
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);
```
The next step is to save the user token from firebase to our global state and update it every time something happens to the user. For that we will use onAuthStateChanged hook from firebase, every time auth changes we will save new user data to our global state. If there is no user, we just set a user to undefined.

```javascript
import { getAuth, signOut, onAuthStateChanged } from "firebase/auth";
import { useSelector, useDispatch } from "react-redux";
import { saveUser } from "./redux/slice/authSlice";

function App() {
  initializeApp(firebaseConfig);
  const auth = getAuth();
  const user = useSelector((state) => state.auth.value);
  console.log("user from state", user);
  const dispatch = useDispatch();
  useEffect(() => {
    onAuthStateChanged(auth, (user) => {
      if (user) {
        dispatch(saveUser(user.refreshToken));
      } else {
        dispatch(saveUser(undefined));
      }
    });
  }, [auth, dispatch]);
```
Now if you go log in and log out, you will see this in your console:

![console logs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7mbv8tbgd8ld129eiyu5.png)

This is is it for this part. In the next part, we will set up protected routes which will be accessible only for logged in users.

## Protected routes

Credit to @medaminefh and his article https://dev.to/medaminefh/protect-your-components-with-react-router-4hf7 where I took the code changed it a bit for this project.

In utils folder create file ProtectedRoute.js and paste this code in:

```javascript
import React from "react";
import { Redirect, Route } from "react-router";
import { useSelector } from "react-redux";
const ProtectedRoute = ({ component: Component }) => {
  const user = useSelector((state) => state.auth.value);
  console.log("user", user);
  return (
    <Route
      render={(props) => {
        if (user) {
          return <Component {...props} />;
        } else {
          return <Redirect to="/" />;
        }
      }}
    />
  );
};

export default ProtectedRoute;
```
ProtectedRoute takes in a component. First we „fetch“the user from the global state using useSelector hook, if the user exists provided component will render. Otherwise, the user will be redirected to the home page.

Now we can use the ProtectedRoute component in our App.js where routes are declared. First, import ProtectedRoute from utils and then simply replace <Route> which you want to protect with <ProtectedRoute>:

```javascript
..
<Route exact path="/reset">
  <Reset />
</Route>

<ProtectedRoute exact path="/protected" component={Secret} />
        
<Route exact path="/">
  <Home />
</Route>
..
```
Now if you are logged in, you will be able to see the protected component, else you will be redirected to the homepage. 

This is it for this tutorial, if you have any questions, feel free to ask!

You can find this repository here: https://github.com/PDavor/react-firebase to make it working just add your firebase configuration!