Profile picture

Experienced software engineer with solid knowledge of Ruby & JavaScript ⚒️.
Amateur explorer, professional thinker 🤔.
Frontend Engineer @remote.

Email and Password Based Authentication with Expo and Firebase Part 1 - Project Setup

August 29, 2021

For a while now, I’ve been using Firebase as my go-to tool to quickly setup an email and password based authentication flow when working with Expo. While there are many other solutions out there, I’ve yet to find one that allows me to get started so quickly as Firebase does.

The goal of this series of blog posts, is to provide a simple example of how to setup Expo and Firebase with email and password based authentication. When done, this app will support sign up, sign in, sign out, email verification, forgot password, and update password. All the code for this series of blog posts is available on this GitHub repository. Let’s jump right in.

Create a New Expo App

If not done already, install the Expo CLI by running npm install --global expo-cli so that the application can be created. Next, create a new application by running expo init --npm and select the blank template. The application can now be served with npm start and opened locally or in the device/simulator of your preference. For simplicity, I’ll be running it through React Native for web, which works out of the box with the Expo SDK. To do so, simply press w in the terminal that’s running the Expo CLI.

expo-cli-options

Expo CLI options to open an app.

Assuming everything went smoothly, the newly created Expo app should now be accessible via a web browser in http://localhost:19006/, where it should display a familiar welcome message.

Create a Firebase Project

Navigate to your Firebase account and create a new project. Once the project is created, click in the sidebar “Authentication” menu item, and enable the “Email/Password” provider.

firebase-email-provider-enabled

“Email/Password” Firebase authentication provider enabled.

Next, go to the project settings and register a web app for the project.

firebase-register-web-app

Select the web app platform to register the web app.

Finally, add the Firebase SDK to the web app (this configuration will later on be used to initialize the Firebase app in the Expo project).

firebase-sdk-configuration-example

Firebase SDK configuration example.

Configure Expo and Firebase

It’s time to use the Firebase project configuration in the Expo app. To do so, first install the Firebase SDK by running expo install firebase. Additionally, install react-native-dotenv by running npm install react-native-dotenv, so that environment variables can be imported in the app via an .env file. Next, add the module:react-native-dotenv plugin to the default Expo babel.config.js file.

module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      ['module:react-native-dotenv'], // Add this
    ],
  };
};

babel.config.js configuration file.

Create an .env file in the root directory of the project by running touch .env, and fill it in with the correct Firebase SDK configuration details. I’ve prefixed them with FIREBASE_ so that it’s clear what these are for.

FIREBASE_API_KEY=
FIREBASE_AUTH_DOMAIN=
FIREBASE_PROJECT_ID=
FIREBASE_STORAGE_BUCKET=
FIREBASE_MESSAGING_SENDER_ID=
FIREBASE_APP_ID=

Example of an .env file. Fill it in with the Firebase SDK web app project configuration.

Create the app’s API directory by running mkdir -p src/api and an index file within it with touch src/api/index.js. This is where the Firebase app will be initialized. To do so, use the environment variables.

import firebase from 'firebase';
import {
  FIREBASE_API_KEY,
  FIREBASE_AUTH_DOMAIN,
  FIREBASE_PROJECT_ID,
  FIREBASE_STORAGE_BUCKET,
  FIREBASE_MESSAGING_SENDER_ID,
  FIREBASE_APP_ID,
} from '@env'

const firebaseConfig = {
  apiKey: FIREBASE_API_KEY,
  authDomain: FIREBASE_AUTH_DOMAIN,
  projectId: FIREBASE_PROJECT_ID,
  storageBucket: FIREBASE_STORAGE_BUCKET,
  messagingSenderId: FIREBASE_MESSAGING_SENDER_ID,
  appId: FIREBASE_APP_ID,
};

firebase.initializeApp(firebaseConfig);

Finally, import this file in App.js (located in the root directory):

import './src/api'; // Import the Firebase API configuration file
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

// Rest of the file omitted...

Application Structure and Dependencies

To simplify the application, I’ll be using the following libraries (installation instructions are outlined below each of them). Note that none of these libraries are technically required, but they will simplify getting up and running.

  • NativeBase: mobile-first, accessible components for React Native & Web.

    npm install native-base styled-components styled-system
    expo install react-native-svg
    expo install react-native-safe-area-context
  • Formik: create forms, manage, and validate their state.

    npm install formik
  • Yup: schema builder for value parsing and validation (which integrates nicely with Formik).

    npm install yup
  • React Navigation: routing and navigation for Expo and React Native apps.

    npm install @react-navigation/native
    expo install react-native-screens react-native-safe-area-context

Let’s now create the “application structure”. The application structure will use a “feature-based” approach, where each feature (i.e., sign up, email verification, etc) will be contained within a directory.

src/
  Root.js
  api/ # API-only methods (Firebase)
  components/ # Re-usable components (among many features)
  features/
    sign-up/
      components/ # Components used by the sign-up feature only
      screens/ # Container type component(s) which setup layout/structure and higher level logic

The first step is to create the Root.js file. To do so, copy App.js by running cp App.js src/Root.js, then remove App.js (rm App.js), and update the package.json file so that main points to src/Root.js:

"main": "src/Root.js"

Next, replace the contents of Root.js so that it imports the Firebase API, setup the native-base provider, and register the root Expo component.

import './api';
import { registerRootComponent } from 'expo';
import React from 'react';
import { StatusBar } from 'expo-status-bar';
import { NativeBaseProvider, Box } from 'native-base';

const Root = () => (
  <NativeBaseProvider>
    <Box>Hello world</Box>
    <StatusBar style="auto" />
  </NativeBaseProvider>
);

registerRootComponent(Root);

Start the Expo server once again by running npm start and make sure the “Hello world” message is correctly shown.

Re-cap

In this blog post, we’ve gone over setting up Expo and Firebase together with the goal of implementing an email and password based authentication system. Additionally, a common set of libraries were installed and setup to make it easier to implement the upcoming features the app will need. In the next blog post, we’ll implement the sign up, email verification, and sign out features.