Creating an app with react and firebase - part three
Tags: basics, react, firebase, authentication
Published: 2017-12-29 19:33:03

---
title: Creating an app with react and firebase - part three
published: true
cover_image: https://thepracticaldev.s3.amazonaws.com/i/n6apugultaaye30h66hj.png
description: Final part of three part series of react and firebase
tags: basics, react, firebase, authentication
---
Welcome to the third and final part of this series on React and Firebase. Before working through this tutorial, make sure you go through parts [one](https://dev.to/aurelkurtula/creating-an-app-with-react-and-firebase---part-one-814) and [two](https://dev.to/aurelkurtula/creating-an-app-with-react-and-firebase---part-two-5hmc). You can clone the project and start following this tutorial by working on the branch named [part-two](https://github.com/aurelkurtula/todo-app-with-react-and-firebase/tree/part-two)

The state of the application so far is that anyone can read and write the todo items that are stored in the database. Today we'll add authentication to the project so that only authenticated users can read and write content. Then of course, we'll further restrict what content each user can read and write, resulting in each users having their own items. 

## 01. Setting up firebase 

We're going to use two methods of authentication. Users will be able to register/login with email and password or through facebook. 

The steps to enable these two methods over at firebase are already covered in my tutorial on [authentication with firebase](https://dev.to/aurelkurtula/introduction-to-authentication-with-firebase-bkd) - you would only need to follow heading "03. Authentication With Email And Password" and "06. Authentication with Facebook" after which you may get back here. 

At this point, you should have enabled the login methods "Email/password" and "Facebook". 

![](https://thepracticaldev.s3.amazonaws.com/i/qdo3ig1efjbvl9s2prtl.png)

Lastly, change the database rules to the following.

    {
      "rules": {
        ".read": "auth != null",
        ".write": "auth != null"
      }
    }

Those rules make sure that no unauthorised user can read or write content. 

From this point forward ... it's code all the way down. 

## 02. Login with facebook

Let's start by setting up facebook authentication. As you've already seen in apps you've used around the web, users click on a link/button and authentication happens through a popup. 

Head over at `./src/fire.js`. There, we'll initialize `FacebookAuthProvider` which is made available by the `firebase` package. 

    import firebase from 'firebase';
    const config = {
       ...
    };
    const fire = firebase.initializeApp(config)
    const facebookProvider = new firebase.auth.FacebookAuthProvider();
    export { fire, facebookProvider }

In the sixth line, or the second from the bottom, we initialize the provider, then export it, making it available for any other file to import.

Let's do that at `./src/App.js` by adding `facebookProvider` as follows: 

    import { fire, facebookProvider } from './fire';

Now let's create an authentication method 

    authWithFacebook=()=>{
      fire.auth().signInWithPopup(facebookProvider)
        .then((result,error) => {
          if(error){
            console.log('unable to signup with firebase')
          } else {
            this.setState({authenticated: true })
          }
        }) 
    }

`authWithFacebook` is a random name I chose, the authentication magic is inside it. Actually it should be very familiar if you read [Introduction to Authentication with Firebase](https://dev.to/aurelkurtula/introduction-to-authentication-with-firebase-bkd) tutorial. 

To test that this works, go ahead and add a link inside the rendered menu

    render() {
      return (
        <BrowserRouter>  
          ...
            <ul className="menu">
              <li><Link to={'/'}>To do</Link></li>
              <li><Link to={'/completed'}>Completed</Link></li>
              <li onClick={this.authWithFacebook}>Login with Facebook</li>
            </ul>
            ...
        </BrowserRouter>   
      );
    }

If authentication is successful we're adding `{authenticated: true}` to the `App` component state. 

But that's not enough. 

As we've already explored in the [authentication with firebase](https://dev.to/aurelkurtula/introduction-to-authentication-with-firebase-bkd) tutorial, the `auth` method gives us the ability to listen to authentication changes

    fire.auth().onAuthStateChanged()

We can make use of it inside the `componentWillMount` "lifecycle" component.

## 03. Accessing data based on authenticated users

The way this works is that when we click on "Login with Facebook" the authentication popup runs. When successful **the `App` component re-renders**. Hence re-running `componentWillMount` making it the perfect place for us to update the application state upon authentication status change. 

At the moment this is the code we have. 

    componentWillMount(){
      this.itemsRef.on('value', data=> {
        this.setState({
          items: data.val()
        })
      })
    }

As it stands it does do the job. If no user is authenticated it will still try to get some data but our firebase database rules will prevent access hence `data.val()` would return nothing. Then when authenticated, the same code re-requests some data and `data.val()` returns our todo items. 

But this would be a nightmare, with the above configuration every user that signs in would have access to the same data, just as before we added authentication. 

We want to store user data in an object which only the user can access. Lets re-write some code:

    class App extends Component {
      state = {
        items: {},
        authenticated: false, 
        loading: true
      }
      itemsRef = '';
      componentWillMount(){
        this.removeAuthListener = fire.auth().onAuthStateChanged(user=>{
          if(user){
            this.itemsRef = fire.database().ref(`items/${user.uid}`)
            this.itemsRef.on('value', data => {
              this.setState({
                authenticated: true, 
                items: data.val(),
                loading: false
              })
            })
          } else {
            this.setState({
              authenticated: false,
              loading: false
            })
          }
        })
      }
      ...

We're basically doing the same thing but with a slight modification. The most notable thing is that we are no longer writing to an `items` object in the database but `items/${user.uid}`. The `uid` is provided by `onAuthStateChanged()`. 

Also, note that we are changing the value of `this.itemsRef` from within `onAuthStateChanged()` so that the user's unique ID is available on the component state level.

Visually we are carving a slot in the non-sql database that looks something like this 

    {
      "items" : {
        "wINebMADEUPCfbvJUSTINZpvCASE1qVRiI2" : {
          "-L1Of70brslQ_JIg922l" : {
            "completed" : false,
            "item" : "item one"
          }
        }
      }
    }

Inside `items` we have `user.uid` and inside that we have the user's items. This way each user now has access only to their own data.

## 04. Login out 

As I've already covered in the [authenticating with firebase](https://dev.to/aurelkurtula/introduction-to-authentication-with-firebase-bkd) tutorial, logging out is very easy: 

    logOut=()=>{
      fire.auth().signOut().then((user)=> {
        this.setState({items:null})   
      })
    }

Then we simply have a button which fires the above method upon click.

## 05. UI design

Before we move on to authenticating with email and password, let's build a better UI. We now have all the means to give users  better UI based on whether they are logged in or not.

Of course the code is going to be in github, so here's a quick overview

In our initial state of the `App` component we have a property `loading: true`, Then in the `componentWillMount` we set `loading: false` indicating that no matter what we do next, the component has mounted. Hence, we are able to render conditional code. 

    render() {
        if (this.state.loading) {
          return (<h3>Loading</h3>)
        }
        return ( ... )
    }

If the condition is true, the `h3` renders on the page. When that's no longer true, the second return statement runs - rendering the code we always had. 

We do the same thing to determine whether a user is logged in or not. We have `authenticated` boolian in our state, which switches from `false` to `true` based on authentication status

At the moment, we are already loading `ItemsComponent` in [part one](https://dev.to/aurelkurtula/creating-an-app-with-react-and-firebase---part-one-814) of this series. We are now going to create another component for the menu. But before we do that, let's write the code we want to return in the `App` component. 

    import Menu from './components/Menu';
    ...
    return (
          <BrowserRouter>  
            <div className="wrap">
              <h2>A simple todo app</h2>
              <Menu 
                logOut={this.logOut} 
                authenticated={this.state.authenticated} 
                authWithFacebook={this.authWithFacebook} 
              />

In order to keep the code clean, we moved the links into their own component. Here is what we are doing there. 

    import React from 'react';
    import { Link } from 'react-router-dom';
    const Menu = (props) => {
      if(props.authenticated){
        return (
          <ul className="menu">
            <li><Link to={'/'}>To do</Link></li>
            <li><Link to={'/completed'}>Completed</Link></li>
            <li className="logOut"  onClick={ props.logOut }>sign out</li>
          </ul>
        );
      } else {
        return (
            <div className="auth">
              <p className="facebook" onClick={props.authWithFacebook}>
                Facebook
              </p>
              <form>
                <label> Email <input type="email" /> </label>
                <label> Password <input type="password" /> </label>
              </form>
            </div>
        );
      }
    }
    export default Menu;

Simple, We check if user is authenticated. If no user is authenticated, we render the facebook button (which executes `authWithFacebook` which we've created above), We also display a form. The end result (with css included, which you're able to get in the repository) looks like this 

![](https://thepracticaldev.s3.amazonaws.com/i/aundq5cinsj5xhcphz7f.png)

## Authenticating with Email and Password

Lets create an `EmailAndPasswordAuthentication` in our `App` Component.

    EmailAndPasswordAuthentication=(e)=>{
      e.preventDefault()
      const email = this.emailInput.value;
      const password = this.passwordInput.value;
      fire.auth().fetchProvidersForEmail(email)
        .then(provider => {
          if(provider.length === 0){
            return fire.auth().createUserWithEmailAndPassword(email, password)
          }else if (provider.indexOf("password") === -1) {
            console.log("you already have an account with " + provider[0] )
        } else {
          return fire.auth().signInWithEmailAndPassword(email, password)
        }
        })
    }

First we prevent the form from running, then get the form input values. Then we run `fetchProvidersForEmail` by providing it with the email received. That method checks firebase authentication to see if a user with the provided email exists. We therefore use an `if` statement to act appropriately. Firstly, we say, if nothing is returned, then create a user, with the email and password provided. If this is the case, if the email is new, then a user is created **and automatically logged in**. 

In the second `if` statement we check if an array with the element of `password` doesn't exist! This is how it works, when users sign in with, say, facebook, their email is stored in firebase. So if someone tries to register with the same email address, `provider` returns `["facebook.com"]`.

Final condition (`else`) returns an array of `["password"]`. I guess that's how firebase chose to tell us whether a user exists and from which provider.

### The form 

Remember that the form is located at `./src/components/Menu.js`, we render it at `./src/App.js` like so 

    <Menu 
        ...
        emailInput={el => this.emailInput = el}
        passwordInput={el => this.passwordInput = el}
        EmailAndPasswordAuthentication={this.EmailAndPasswordAuthentication}
      />

`emailInput` and `passwordInput` will take the element passed to it and attach it to a local variable within the `App` component (`this.emailInput` and `this.passwordInput`) and of course `this.EmailAndPasswordAuthentication` refers to the method we just created. 

Now in  `./src/components/Menu.js` the form looks like this 

    return (
        <div className="auth">
          <p className="facebook" onClick={props.authWithFacebook}>Facebook</p>
          <form 
          onSubmit={(event) => {props.EmailAndPasswordAuthentication(event) }} 
          >
            <label>
              Email <input type="email" ref={ props.emailInput} />
            </label>
            <label>
              Password  <input type="password" ref={ props.passwordInput} />
            </label>
            <input type="submit" value="Register/Login" />
          </form>
        </div>
    );


`ref` sort of hands the element to the props. So in the `App` component, `this.emailInput` would return the same thing as `document.querySelector('input[type="email"]')`. 

## Conclusion 

That's it. We now are able to sign users in with facebook, or email and password. And with that, this mini-project spanned across three posts is complete. The code from this tutorial is at the same github repository in the branch named [part-three](https://github.com/aurelkurtula/todo-app-with-react-and-firebase/tree/part-three).

You can check the previous two posts [here](https://dev.to/aurelkurtula/creating-an-app-with-react-and-firebase---part-one-814) and [here](https://dev.to/aurelkurtula/creating-an-app-with-react-and-firebase---part-two-5hmc)