How to create a Firebase login and sign up in React

Firebase is a system that offers many platforms for devs to build web apps. One of the essential elements in an app is to create users and allow them to login. Let’s see how we can write a Firebase login that is complete yet very simple to implement.

Create your Firebase app

Install Firebase dependencies

Setup the Firebase provider

Use the Firebase login and sign up component

Setup the Firebase login and sign up

Conclusion

Create your Firebase app

You first need to create a Firebase app project so head over to the Firebase console and add a new project. You’ll add the app here.

https://console.firebase.google.com/

Create a project for the Firebase login and sign up

It will launch an assistant that will ask you the name of the project.

Name the project for your Firebase login and sign up

The next screen will ask you if you want to enable analytics. Toggle it off and click the Create project button. It will take a while to provision your project and after that, you’ll get a button to Continue that will take you to the project overview.

You now need to add a Firebase app to the Firebase project. Makes sense? A Firebase project allows you to contain several Firebase apps for iOS, Android, Web, and Unity. For now, let’s create a Web app since we’ll be using React to create our Firebase login.

Add a Web app to the project to work on the Firebase login and sign up

You will be asked to name this app, and you’ll be given the keys that you’ll need to use to connect with Firebase. They’ll look something like:

var firebaseConfig = {
    apiKey: "1A2B3C4D5E6F7G",
    authDomain: "appname-a123b.firebaseapp.com",
    databaseURL: "https://appname-a123b.firebaseio.com",
    projectId: "appname-a123b",
    storageBucket: "appname-a123b.appspot.com",
    messagingSenderId: "1234567890",
};

We’ll use this keys in our React app to configure a provider that will allow us to access Firebase in any component under the provider.

Finally, go into Authentication in the left sidebar, the the Sign-in method tab, and enable the Email/Password authentication.

Enable Email/Password authentication to work on the Firebase login and sign up

You’re all set!

Install Firebase dependencies

Firebase is available for different stacks, including JavaScript and Node.js which is what we’re going to use now. We’re going to install only two dependencies with npm:

  • firebase, that will allow us to access things like the auth library, which we’ll use to perform the login and also creating a new user
  • reactfire, a collection of useful tools to work with Firebase in React. We’ll use their useFirebaseApp to connect to the context and access Firebase

Let’s install them with

npm i firebase reactfire

The structure of the React app will be very simple, as follows:

|-- index.js
|-- App.js
|-- FirebaseUser
    |-- index.js

and they’ll be related as follows:

index.js --import--> ./App.js --import--> ./FirebaseUser

Setup the Firebase provider

Let’s write the first file for the Firebase login and signup! We don’t actually need to write it, because this should be added to the file where you’re issuing ReactDOM.render(), in our case it will be index.js:

import { FirebaseAppProvider } from 'reactfire';

const firebaseConfig = {
    apiKey: "1A2B3C4D5E6F7G",
    authDomain: "appname-a123b.firebaseapp.com",
    databaseURL: "https://appname-a123b.firebaseio.com",
    projectId: "appname-a123b",
    storageBucket: "appname-a123b.appspot.com",
    messagingSenderId: "925199572988",
    appId: "1:123456789:web:12a34b56c78d90e"
};

This imports the FirebaseAppProvider and adds the configuration keys you’ll pass to it. You can now wrap the root component, which in our case is App with the provider:

ReactDOM.render(
  <FirebaseAppProvider firebaseConfig={ firebaseConfig }>
    <App />
  </FirebaseAppProvider>,
  document.getElementById('root')
);

Great! Now all the components below will be able to access Firebase!

Use the Firebase login and sign up component

Let’s write now the App component where we’ll import and use the FirebaseUser component to create and login a user. There’s nothing really Firebase related here. We’re going to implement a login and signup using the same component so you can see how we can reuse the code, so in this component we’ll implement a pair of buttons that when clicked, will render the FirebaseUser in a login mode or a sign up mode:

import React, { useState } from 'react';
import FirebaseUser from './FirebaseUser';

function App() {
  const [ signInOrUp, setSignInOrUp ] = useState( '' );
  return (
    <div className="App">
      <h1>Firebase login</h1>
      {
        signInOrUp ? (
          <FirebaseUser action={ signInOrUp } />
        ) : (
          <>
            <button type="button" onClick={ () => setSignInOrUp( 'signin' ) } >Log in with existing user</button>
            <button type="button" onClick={ () => setSignInOrUp( 'signup' ) } >Create a new user</button>
          </>
        )
      }
    </div>
  );
}

export default App;

Setup the Firebase login and sign up

We’ll create a component for this. We first need to import some modules:

import React, { useState } from 'react';
import { useFirebaseApp } from 'reactfire';
import 'firebase/auth';

We’ll useState for a few things, from knowing whether user is authenticated to set errors. We’re going to use the useFirebaseApp hook to access the Firebase connection. This is only possible because we setup the Firebase provider in the previous step, and it’s only available under the hierarchy where it was added. Finally, we’ll import the auth library so we can call the Firebase methods to create users and login. This is an efficient way because we’re only loading this library, and not others like firestore for the NoSQL database, or messaging for messages and notifications.

Next we’ll add a quick hook to manage our input fields:

const useField = () => {
	const [ value, setValue ] = useState( '' );
	return { value, onChange: x => setValue( 'string' === typeof x ? x : x.target.value ) };
};

And finally the full component, which we’ll break it down below to point the most interesting portions, those related to the Firebase login and signup.

function FirebaseUser ( { action = 'signin' }) {
    const email = useField();
    const password = useField();
    const [ auth, setAuth ] = useState( null );
    const [ error, setError ] = useState( '' );
    const firebase = useFirebaseApp();
    const setReceivedData = data => setAuth( data );
    const setReceivedError = error => setError( error.message );

    const signIn = e => {
        e.preventDefault();
        setError( '' );
        firebase.auth()
            .signInWithEmailAndPassword( email.value, password.value )
            .then( setReceivedData )
            .catch( setReceivedError );
    };
    
    const signUp = e => {
        e.preventDefault();
        setError( '' );
        firebase.auth()
            .createUserWithEmailAndPassword( email.value, password.value )
            .then( setReceivedData )
            .catch( setReceivedError );
    };

    const manage = 'signin' === action 
        ? {
            success: `Logged in as ${ auth?.user.email ?? '' }`,
            method: signIn,
            label: 'Sign In'
        }
        : {
            success: `Signed up as ${ auth?.user.email ?? '' }`,
            method: signUp,
            label: 'Sign Up'
        };

    return (
        <div>
            {
                auth ? (
                    <p>{ manage.success }</p>
                ) : (
                    <>
                        <form onSubmit={ manage.method }>
                            <input { ...email } placeholder="email" />
                            <input { ...password } type="password" placeholder="password" />
                            <button type="submit">{ manage.label }</button>
                            {
                                error && <p>{ error }</p>
                            }
                        </form>
                    </>
                )
            }
        </div>
    );
}

export default FirebaseUser;

First, we hook to the Firebase instance:

const firebase = useFirebaseApp();

As pointed before, this is possible because we previously wrapped the App component with the Firebase provider. Now that we’re hooked to Firebase, we can use the auth functionality and call signInWithEmailAndPassword:

const signIn = e => {
        e.preventDefault();
        setError( '' );
        firebase.auth()
            .signInWithEmailAndPassword( email.value, password.value )
            .then( setReceivedData )
            .catch( setReceivedError );
};

When it succeeds, it will set the data returned and the form fields will be replaced with

Logged in as ${ auth?.user.email ?? '' }

The data returned is a large object with very interesting properties so it’s worth adding a console.log() to our setReceivedData() function to see what else it includes.

The process to create a user is similar, except we use the function createUserWithEmailAndPassword().

Conclusion

To test our Firebase login and sign up, you can try logging in for a user that doesn’t exist so you can see the errors. After that, create a user and then log in as the user.

Demo of the Firebase login and sign up system in React
Demo of the Firebase login and sign up.
Fun fact: Chrome complains that the password 123456 I’m using for testing is compromised, which is true.

If you now go back to the Firebase app > Authentication > Users you’ll see the new user (you might need to use the refresh button next to Add user).

The users created by the Firebase login and sign up system in React

To recap, the essential steps to integrate Firebase in our React app are:

  • setup the Firebase provider and wrap the root component (or the root of the hierarchy where you want to use it)
  • hook to the Firebase provider using useFirebaseApp
  • use the authentication functions!

Check the GitHub repository at https://github.com/eliorivero/firebase-login-sign-up. The only difference with this one is that I’m loading the keys to configure Firebase from an .env file to avoid exposing them publicly.

If you have any questions, let me know in the comments below!

Leave a Reply