Authentication in React with Firebase

Written by NaguiHW | Published 2020/05/27
Tech Story Tags: react | reactjs | authentication | logout | email-signup | firebase | google | programming

TLDR Firebase provides authentication backend services easy to use. It supports authentication using passwords, phone numbers, popular social networks like Google, Facebook and Twitter. In this tutorial we are going to create a React web app with a React app. We have to install the Firebase configuration that we created before. We then wrap the entire app with FirebaseApp Provider and this provider needs to receive the firebase configuration. We are then given a code that we will then have to put in our projects. For this project I am going to disable Google Analytics.via the TL;DR App

Sometimes we want to implement authentication for multiple reasons and we don't want to create an API just for the authentication or maybe we are not backend developers. That's why Firebase provides authentication backend services easy to use. It supports authentication using passwords, phone numbers, popular social networks like Google, Facebook and Twitter, and more.

Requirements

First of all, we have to have a Google account (Gmail account). If you don't have an account, create it before starting.

Firebase Configurations

We have to go to their website, log in if we are not logged in, and click on
Get Started
.
And after that, we click on
Add project
.
We have to put a name for our project. For this tutorial I am going to name it react-authentication.
Click on
continue
.
For this project I am going to disable Google Analytics. It doesn't affect in anything, so you could enable it if you want.
Finally we click on
Create project
.
When we see this image, it means that we are ready to go.
Click on
Continue
.
Firebase is not only for web applications, it is also for mobil devices and unity games. But in this case we are going to create a React web app.
Click on the marked icon.
Now, we have to put a nickname for our application. It doesn't matter which nickname we put it, after all, we are the only ones that are going to see it. I recommend you put a nickname related to the project.
Click on
Register app
.
After a few seconds Firebase is going to give us a code that we will then have to put in our projects.
Now we have to go to the
authentication
area.
Click on
Set up sign-in method
.
We can see that we have a lot of types of authentication but in this tutorial we are just cover the
Email/Password
method.
Before clicking the
Email/Password
method, we can see below that we have the authorized domains. By default there are 3, but you can add more domains.
Now we are going to enable just the first option. The second option is like it says. When we try to login, google is going to send us a link to our email to login.
And that's it. We are done with the Firebase configuration.

React App Configurations

First of all we have to install the dependencies that are going to help us:
npm i --save firebase reactfire@next
To keep everything in order we are going to create a file named
firebaseConfig.js
in our
src
folder. Inside of the firebaseConfig,js file, we add it the json code and export it.
// src/firebaseConfig.js
const firebaseConfig = {
  apiKey: "AIzaSyBSo7NZouVtr-G36eLbFGjXv_IN7cBBn30",
  authDomain: "react-authentication-2c83f.firebaseapp.com",
  databaseURL: "https://react-authentication-2c83f.firebaseio.com",
  projectId: "react-authentication-2c83f",
  storageBucket: "react-authentication-2c83f.appspot.com",
  messagingSenderId: "194995380667",
  appId: "1:194995380667:web:5e5dd9db459ab8a21da49e"
}

export default firebaseConfig;
Now, to Firebase work, we have to wrap the entire app with FirebaseAppProvider and this provider needs to receive the firebase configuration that we created before.
import React, { Suspense } from 'react';
import ReactDOM from 'react-dom';
import { FirebaseAppProvider } from 'reactfire';
import firebaseConfig from './firebaseConfig';
import App from './App';
import './index.css';

ReactDOM.render(
  <FirebaseAppProvider firebaseConfig={firebaseConfig}>
    <Suspense fallback={<h3>Loading...</h3>}>
      <React.StrictMode>
        <App />
      </React.StrictMode>
    </Suspense>
  </FirebaseAppProvider>,
  document.getElementById('root')
);
If you don't know what is suspense component from React, you can check it here.
To see if everything is working well, we could import
useFirebaseApp
and do a
console.log()
to see in our web console what is going on. We have to add the
userFirebaseApp
in our
App.js
file
import React from 'react';
import './App.css';
import { useFirebaseApp } from 'reactfire';

function App() {
  const firebase = useFirebaseApp();
  console.log(firebase);
  return (
    // Some code
  );
}

export default App;
We can delete the console.log() that we created before so we can continue with the tutorial.

Authentication

Sign Up

First, let's create a
Sign Up
component.
import React, { useState } from 'react';
import './Signup.css';

const Signup = () => {
  // User State
  const [user, setUser] = useState({
    nickname: '',
    email: '',
    password: '',
    error: '',
  });

  // onChange function
  const handleChange = e => {
    setUser({
      ...user,
      [e.target.name]: e.target.value,
      error: '',
    })
  };

  // Submit function (Create account)
  const handleSubmit = e => {
    e.preventDefault();
    // Sign up code here.
  }

  return (
    <>
      <h1>Sign up</h1>
      <form onSubmit={handleSubmit}>
        <input type="text" placeholder="Nickname" name="nickname" onChange={handleChange}/><br />
        <input type="text" placeholder="Email" name="email" onChange={handleChange}/><br />
        <input type="password" placeholder="Password" name="password" onChange={handleChange}/><br />
        <button type="submit">Sign Up</button>
      </form>
      {user.error && <h4>{user.error}</h4>}
    </>
  )
};

export default Signup;
Lets explain:
  • First we created the user state with React Hooks. If you are not familiar with Reac hooks, you can check the documentation here.
  • We have this
    handleChange
    function that updated the state when the user does a change in the inputs. Also reset the error message to hide it.
  • The
    handleSubmit
    function is where we are going to send the information to Firebase.
  • The
    nickname
    input is optional, we are going to see why in the next steps.
And this is the result. I added minor styling so your form could look diferent.
Now we are going to finish the
handleSubmit
function.
import React, { useState } from 'react';
import { useFirebaseApp } from 'reactfire';
import 'firebase/auth'
import './Signup.css';

const Signup = () => {
  // Previous code...

  // Import firebase
  const firebase = useFirebaseApp();

  // Submit function (Create account)
  const handleSubmit = async(e) => {
    e.preventDefault();
    // Sign up code here.
    await firebase.auth().createUserWithEmailAndPassword(user.email, user.password)
      .then(result => {
        // Update the nickname
        result.user.updateProfile({
          displayName: user.nickname,
        })
      }).catch(error => {
        // Update the error
        console.log(error);
        setUser({
          ...user,
          error: error.message,
        })
      })
  }

  return (
    // Previous code...
  )
};

export default Signup;
  • First, we have to import
    useFirebaseApp
    and
    firebase/auth
    , so we can start to create the user.
  • Assign the
    useFirebaseApp
    to
    firebase
    const.
  • The handleSubmit function has to be an async/await function.
  • firebase.auth().createUserWithEmailAndPassword()
    will recive just an email and a password, like it says in the name. That's why making a
    nickname
    is optional.
  • If we added the nickname option, we have to update the profile, that is why we use
    user.updateProfile()
    . This receives an object with 2 optional parameters:
    displayName
    to update the username and the
    photoURL
    to add a picture avatar. In this tutorial we are just using
    displayName
    .
  • And finally in the
    catch
    part we just update the error message.
With this code we could say that is done, and yes it is, we got what we wanted, but we can improve it.
Right now when we Sign up, we don't know if the email is a valid or not, also Firebase automatically logged us in and maybe we don't want that, so let's edit the
handleSubmit
function.
    const handleSubmit = async(e) => {
        e.preventDefault();
        // Sign up code here.
        await firebase.auth().createUserWithEmailAndPassword(user.email, user.password)
          .then(result => {
            // Update the nickname
            result.user.updateProfile({
              displayName: user.nickname,
            });
    
            // URL of my website.
            const myURL = { url: 'http://localhost:3000/' }
    
            // Send Email Verification and redirect to my website.
            result.user.sendEmailVerification(myURL)
              .then(() => {
                setUser({
                  ...user,
                  verifyEmail: `Welcome ${user.nickname}. To continue please verify your email.`,
                })
              })
              .catch(error => {
                setUser({
                  ...user,
                  error: error.message,
                })
              })
    
            // Sign Out the user.
            firebase.auth().signOut();
          }).catch(error => {
            // Update the error
            setUser({
              ...user,
              error: error.message,
            })
          })
    }
    We added 3 new things.
    • myURL
      is an object that contains the url of my website.
    • result.user.sendEmailVerification()
      send an email verification and we passed
      myURL
      object to add a link to redirect us to our website.
    • firebase.auth().signOut()
      signed us out, so that we do not log in automatically and wait for the email confirmation.

    Log In

    The Log in is easy. Actually is similar to the previous code.
    import React, { useState } from 'react';
    import { useFirebaseApp } from 'reactfire';
    import 'firebase/auth'
    import './Signup.css';
    
    const Login = () => {
      // User State
      const [user, setUser] = useState({
        email: '',
        password: '',
        error: '',
      });
    
      // onChange function
      const handleChange = e => {
        setUser({
          ...user,
          [e.target.name]: e.target.value,
          error: '',
        })
      };
    
      // Import firebase
      const firebase = useFirebaseApp();
    
      // Submit function (Log in user)
      const handleSubmit = e => {
        e.preventDefault();
        // Log in code here.
        firebase.auth().signInWithEmailAndPassword(user.email, user.password)
          .then(result => {
            if (!result.user.emailVerified) {
              setUser({
                ...user,
                error: 'Please verify your email before to continue',
              })
              firebase.auth().signOut();
            }
          })
          .catch(error => {
            // Update the error
            setUser({
              ...user,
              error: error.message,
            })
          })
      }
    
      return (
        <>
          <h1>Log In</h1>
          <form onSubmit={handleSubmit}>
            <input type="text" placeholder="Email" name="email" onChange={handleChange}/><br />
            <input type="password" placeholder="Password" name="password" onChange={handleChange}/><br />
            <button type="submit">Log in</button>
          </form>
          {user.error && <h4>{user.error}</h4>}
        </>
      )
    };
    
    export default Login;
    
    The most relevant changes are:
    • We just have 2 inputs: email and password.
    • Instead of use
      createUserWithEmailAndPassword()
      , we use
      signInWithEmailAndPassword()
      .
    • We have to verify if the email was confirmed or not.

    Log out

    Log out is just a button that shows up only when the user is connected.
    import React from 'react';
    import { useFirebaseApp } from 'reactfire';
    import 'firebase/auth'
    
    const Logout = () => {
      // Import firebase
      const firebase = useFirebaseApp();
    
      // Log out function
      const handleClick = () => {
        firebase.auth().signOut();
      }
    
      return (
        <>
          <button type="button" onClick={handleClick}>Log Out</button>
        </>
      )
    };
    
    export default Logout;
    We use
    firebase.auth().signOut()
    . The same function that we use to prevent automatically logged in.
    And practically we are done.
    If we want to know if the user is connected or not, we can use
    useUser 
    function from
    reactfire
    .
    import React from 'react';
    import Signup from './Signup';
    import Login from './Login';
    import Logout from './Logout';
    import { useUser } from 'reactfire';
    import './App.css';
    
    function App() {
      const user = useUser();
      return (
        <div className="App">
          {
            user &&
            <Logout />
          }
          {
            !user &&
            <>
              <Signup />
              <Login />
            </>
          }
        </div>
      );
    }
    
    export default App;
    I put it in the App file to render the components depending if the user is connected or not.
    You can see the entire repo here.

Published by HackerNoon on 2020/05/27