Handling Firebase authentication in a React-Native app
Tags: reactnative, tutorial, javascript, mobile
Published: 2021-12-27 23:02:55

## Introduction

[Firebase](https://firebase.google.com/) is a backend service provider that enables the building of software applications. It offers services ranging from authentication, real-time database, machine learning and storage. Over the years, firebase has been widely adopted by many companies around the world as a go-to platform in cases of building out software applications quickly. 

> In this tutorial, we will explore how to enable a Firebase email and password authentication in a React-Native app. This article will focus solely on implementing the signup, sign in and signout functionalities in a React-Native app.

---

## Prerequisites

Before engaging this article, a good understanding of the following is required :

- React-Native and Expo
- Firebase
- React Navigation
- Development Environment (Visual Studio Code)

---

## Getting Started

This article follows distinct steps of achieving the goal of enabling Firebase authentication in a React-Native app. These steps include :

- Setting up a development environment
- Installing Firebase
- Setting up Firebase app
- Integrating Firebase in the React-Native app
- Building up authentication screens
- Handling Firebase authentication
- Observing Firebase user state
- Conclusion

---

## Setting up a development environment

Create a new React-Native project in a terminal window(command line, Powershell, Git Bash, etc) using expo-cli. Expo initializes a new project for building your React-Native app.

```javascript
//creates a new React-Native project

expo init [project name]
```

---

## Installing Firebase

After creating the React-Native app with Expo, install the Firebase SDK by running this command.
```javascript
yarn add firebase

//If you are using npm, run this instead
npm install firebase
```

---

## Setting up Firebase project

![Adding a new Firebase project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v76porsasutaj64uaa04.png)
Get started by creating a new firebase project. Click on the card that says **Add Project** to create a new firebase project for the application


![Authentication image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9v7e61574azwgz2m8ysx.png)

Once the project has been created and registered, enable the email and password authentication method. It is under the same section as phone and anonymous authentication method, but only the email and password authentication method is required for now.



---

## Integrating Firebase in the React-Native app

Firebase is built for rendering backend services, that is why it’s called Backend as a Service(Baas). In the React-Native app created with Expo, create a folder called **services** in the root and then create a file called `Firebase.js` in it.

In `Firebase.js` import `firebase` as thus :
```javascript
import firebase from "firebase"
```

Go to the Firebase project, navigate to the project settings and copy the configuration object containing keys and identifiers for the app.

![Firebase Configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ulsl7qp6ivb5l3ckpuuv.png)

Paste the copied object directly under the `firebase` import statement in `Firebase.js`

Below the firebaseConfig object, add the code below

```javascript
// Initialize Firebase
if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig);
}
```
This piece of code enables/initializes firebase in our React-Native app.

---

## Building up authentication screens
Create a `SignUp.js` file and `SignIn.js` file and a `Home.js` file. These files handles the beautiful UI of the app.

`SignUp.js`
```javascript
import React, { useState } from "react";
import { Pressable, StyleSheet, Text, TextInput, Image, View } from "react-native";
import { Ionicons } from "@expo/vector-icons";

const SignUp = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const [visible, setVisibility] = React.useState({ name: "eye-off" });

  //Toggles the eye icon to show the password
  const ToggleVisibilty = () => {
    if (visible.name === "eye") {
      setVisibility({ name: "eye-off" });
    } else {
      setVisibility({ name: "eye" });
    }
  };

  //Handles password visibility when the eye icon is pressed
  const secureTextEntry = () => {
    if (visible.name === "eye") {
      return false;
    } else if (visible.name === "eye-off") {
      return true;
    }
  };

  //Handles email input
  const handleEmailChange = (text) => {
    setEmail(text);
  };

  //Handles password input
  const handlePasswordChange = (text) => {
    setPassword(text);
  };

  //Handles confirm password input
  const handleConfirmPasswordChange = (text) => {
    setConfirmPassword(text);
  };

  //Handles sign up
  const handleSubmit = async () => {
   console.log("User signed up!")
  };

  return (
    <View style={styles.container}>
      <View style={styles.headerContainer}>
        <Text style={{ fontSize: 40, fontFamily: "QuicksandBold", color: "#fff" }}>Create</Text>
        <Image
          source={require("../../assets/images/broxnbg.png")}
          style={{
            height: 30,
            width: 50,
            top: 9,
            marginRight: 5,
            transform: [{ rotate: "-10deg" }],
          }}
        />
        <Text style={{ fontSize: 40, fontFamily: "QuicksandBold", color: "#fff" }}>account</Text>
      </View>
      <View style={styles.form}>
        <TextInput
          style={styles.email}
          defaultValue={email}
          onChangeText={handleEmailChange}
          textContentType="emailAddress"
          placeholder="Email Address"
          placeholderTextColor="grey"
          keyboardType="email-address"
          returnKeyType="next"
        />
        <View style={styles.passwordContainer}>
          <TextInput
            style={styles.password}
            defaultValue={password}
            onChangeText={handlePasswordChange}
            placeholder="Enter Password"
            placeholderTextColor="grey"
            returnKeyType="next"
            secureTextEntry={secureTextEntry()}
            textContentType="password"
            keyboardType="default"
            autoCorrect={false}
          />
          <Ionicons
            name={visible.name}
            size={24}
            color="#1da"
            style={styles.eyeContainer}
            onPress={ToggleVisibilty}
          />
        </View>
        <View style={styles.passwordContainer}>
          <TextInput
            style={styles.password}
            defaultValue={confirmPassword}
            onChangeText={handleConfirmPasswordChange}
            placeholder="Confirm Password"
            placeholderTextColor="grey"
            returnKeyType="go"
            secureTextEntry={secureTextEntry()}
            textContentType="password"
            keyboardType="default"
            autoCorrect={false}
          />
        </View>
        <Pressable
          style={styles.registerContainer}
        >
          <Text style={styles.register}>want to sign in?</Text>
        </Pressable>
        <Pressable style={styles.button} onPress={handleSubmit}>
          <Text style={{ fontFamily: "QuicksandBold", fontSize: 20 }}>SIGN UP</Text>
        </Pressable>
      </View>
    </View>
  );
};

export default SignUp;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
    width: "100%",
    height: "100%",
    backgroundColor: "#0C0C1C",
  },
  headerContainer: {
    flexDirection: "row",
    width: "80%",
    height: 50,
    marginBottom: 40,
    top: -20,
  },
  form: {
    width: "80%",
    flexDirection: "column",
    alignItems: "center",
    justifyContent: "center",
    top: -40,
  },
  email: {
    width: "100%",
    height: 60,
    backgroundColor: "#0ff1",
    borderRadius: 5,
    marginBottom: 35,
    padding: 10,
    fontSize: 18,
    fontFamily: "QuicksandBold",
    color: "#fff",
  },
  password: {
    width: "85%",
    height: 60,
    borderRadius: 5,
    marginBottom: 35,
    padding: 10,
    fontSize: 18,
    fontFamily: "QuicksandBold",
    color: "#fff",
  },

  passwordContainer: {
    flexDirection: "row",
    width: "100%",
    height: 60,
    backgroundColor: "#0ff1",
    borderRadius: 5,
    marginBottom: 35,
  },
  eyeContainer: {
    position: "absolute",
    right: 10,
    top: 20,
  },

  button: {
    width: "100%",
    height: 50,
    backgroundColor: "#1da",
    borderRadius: 5,
    justifyContent: "center",
    alignItems: "center",
    top: 30,
    padding: 10,
  },

  register: {
    fontFamily: "QuicksandBold",
    color: "#fff",
    fontSize: 18,
  },
  registerContainer: {
    top: -20,
    flexDirection: "row",
    alignSelf: "flex-end",
  },
});
```
That is quite a lot of code!




![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mht1k7l3z5tlhjsw5wk8.png)

But it does look good!

The `SignUp.js` consists of `TextInput` fields for user email, user password and confirm password.

The `SignUp` component consists of the following functions :
- The `handleEmailChange()`, `handlePasswordChange()` and `handleConfirmPasswordChange()` functions enables the update of values of the different `TextInput` with the `onChangeText` attribute.

- The `ToggleVisibility()` function switches the eye icon depending on the visibility of the password.

- `secureTextEntry()` function handles password visibility when the eye icon is pressed. 

`SignIn.js`
```javascript
import { useNavigation } from "@react-navigation/core";
import React, { useState } from "react";
import { Image, Pressable, StyleSheet, Text, TextInput, View } from "react-native";
import { Ionicons } from "@expo/vector-icons";

const signIn = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [visible, setVisibility] = React.useState({ name: "eye-off" });

  const ToggleVisibilty = () => {
    if (visible.name === "eye") {
      setVisibility({ name: "eye-off" });
    } else {
      setVisibility({ name: "eye" });
    }
  };

  const secureTextEntry = () => {
    if (visible.name === "eye") {
      return false;
    } else if (visible.name === "eye-off") {
      return true;
    }
  };

  const handleEmailChange = (text) => {
    setEmail(text);
  };

  const handlePasswordChange = (text) => {
    setPassword(text);
  };

  const handleSignInClick = async () => {
    await handleSignIn(email, password);
    console.log("Login successful");
  };

  return (
    <View style={styles.container}>
      <View style={styles.headerContainer}>
        <Text
          style={{
            fontSize: 40,
            fontFamily: "QuicksandBold",
            color: "#fff",
          }}
        >
          Sign in
        </Text>
        <Image
          source={require("../../assets/images/broxnbg.png")}
          style={{ height: 30, width: 50, top: 9, transform: [{ rotate: "-10deg" }] }}
        />
      </View>
      <View style={styles.form}>
        <TextInput
          style={styles.email}
          defaultValue={email}
          onChangeText={handleEmailChange}
          textContentType="emailAddress"
          placeholder="Email Address"
          placeholderTextColor="grey"
          returnKeyType="next"
        />
        <View style={styles.passwordContainer}>
          <TextInput
            style={styles.password}
            defaultValue={password}
            onChangeText={handlePasswordChange}
            placeholder="Enter Password"
            placeholderTextColor="grey"
            returnKeyType="go"
            secureTextEntry={secureTextEntry()}
            textContentType="password"
            keyboardType="default"
            autoCorrect={false}
          />
          <Ionicons
            name={visible.name}
            size={24}
            color="#1da"
            style={styles.eyeContainer}
            onPress={ToggleVisibilty}
          />
        </View>
        <Pressable style={styles.forgotContainer}>
          <Text style={styles.forgot}>Forgot Password?</Text>
        </Pressable>
        <Pressable style={styles.button} onPress={handleSignInClick}>
          <Text style={{ fontFamily: "QuicksandBold", fontSize: 20 }}>SIGN IN</Text>
        </Pressable>
        <Pressable
          style={{
            alignItems: "center",
            justifyContent: "center",
            top: "50%",
            height: 30,
          }}
        >
          <Text
            style={{
              alignItems: "center",
              justifyContent: "center",
              fontFamily: "QuicksandBold",
              fontSize: 16,
              color: "white",
            }}
          >
            Do not have an account? Register
          </Text>
        </Pressable>
      </View>
    </View>
  );
};

export default SignIn;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
    width: "100%",
    height: "100%",
    backgroundColor: "#0C0C1C",
  },
  headerContainer: {
    flexDirection: "row",
    width: "80%",
    height: 50,
    marginBottom: 40,
    top: -20,
  },
  form: {
    width: "80%",
    flexDirection: "column",
    alignItems: "center",
    justifyContent: "center",
    top: -40,
  },
  email: {
    width: "100%",
    height: 60,
    backgroundColor: "#0ff1",
    borderRadius: 5,
    marginBottom: 35,
    padding: 10,
    fontSize: 18,
    fontFamily: "QuicksandBold",
    color: "#fff",
  },
  password: {
    width: "85%",
    height: 60,
    borderRadius: 5,
    marginBottom: 35,
    padding: 10,
    fontSize: 18,
    fontFamily: "QuicksandBold",
    color: "#fff",
  },

  passwordContainer: {
    flexDirection: "row",
    width: "100%",
    height: 60,
    backgroundColor: "#0ff1",
    borderRadius: 5,
    marginBottom: 35,
  },
  eyeContainer: {
    position: "absolute",
    right: 10,
    top: 20,
  },

  button: {
    width: "100%",
    height: 50,
    backgroundColor: "#1da",
    borderRadius: 5,
    justifyContent: "center",
    alignItems: "center",
    top: 30,
    padding: 10,
  },

  forgot: {
    fontFamily: "QuicksandBold",
    color: "#fff",
    fontSize: 18,
  },

  forgotContainer: {
    top: -20,
    flexDirection: "row",
    alignSelf: "flex-end",
  },
});
```
The `SignIn` component is basically the same as the the `SignUp` component. It just has a difference of one less `TextInput`.




![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b7xew1caaenirz5qhnvg.png)

---

## Handling Firebase authentication

In `Firebase.js` just below the firebase initialization snippet, add a function to handle user sign up and another function to handle user sign in. 

**Handling user sign up**
```javascript
// signup function
export const handleSignUp = async (email, password) => {
  await firebase
    .auth()
    .createUserWithEmailAndPassword(email, password)
    .then(() => {
      console.log(firebase.auth().currentUser);
      const user = firebase.auth().currentUser;
    })
    .catch((error) => {
      console.error(error);
    });
};
```
This function enables user to create an account with an email and password using `createUserwithEmailandPassword` method provided by firebase auth API.

`handleSignUp` takes in two parameters `email` and `password`. These parameters takes the value of the current state of `TextInput` when `handleSignUp` function is called.

The `handleSignUp` function is being exported, which means that we need it to be imported into `SignUp.js` for usage.

In `SignUp.js` import `handleSignup` function as thus:
```javascript
//importing handleSignUp() function
import { handleSignUp } from "../../services/firebase/firebaseConfig";
```

After importing the `handleSignUp` function, we call it inside the `handleSubmit` function.
```javascript
 //Handles sign up
  const handleSubmit = async () => {
    if (email === "" && password !== confirmPassword && password === "" && confirmPassword === "") {
      console.error("Invalid Credentials");
    } else {
      try {
        await handleSignUp(email, password);
      } catch (error) {
        console.error(error);
      }
    }
  };
```
This function is called when the submit button is clicked. In the `handleSubmit` function, it checks if the email, password and confirm password value provided are valid. If any of the `TextInput` is empty, it returns an error message. If the email provided is already in use, it also returns an error.

**Handling user sign in**
```javascript
// sign in function
export const handleSignIn = async (email, password) => {
  await firebase
    .auth()
    .signInWithEmailAndPassword(email, password)
    .then(() => {
      console.log(firebase.auth().currentUser);
    })
    .catch((error) => {
      console.error(error);
    });
};
```
`handleSignIn` function enables user to sign in to an already created account with an email and password using `SignInwithEmailandPassword` method provided by firebase auth API.

The `handleSignIn` function makes sure that a request is made to the firebase API in order for a user to login to their account.

The `handleSignIn` function is also being exported, which implies that it needs to be accessed or called it in `SignIn.js` 

In `SignIn.js` import `handleSignIn` function as thus:
```javascript
//importing handleSignUp function
import { handleSignIn } from "../../services/firebase/firebaseConfig";
```

After importing the `handleSignIn` function, we call it inside the `handleSubmit` function.
```javascript
 //Handles sign  in
  const handleSubmit = async () => {
    if (email === "" || password === "") {
      console.error("Invalid Credentials");
    } else {
      try {
        await handleSignIn(email, password);
      } catch (error) {
        console.error(error);
      }
    }
  };
```
This function is called when the submit button is pressed. In the `handleSubmit` function, it checks for email and password value validity. If any of the `TextInput` is empty, it returns an error message. It also returns an error if the user does not exist in the app. 

`Profile.js`
```javascript
import React from "react";
import { Pressable, StyleSheet, Text, View } from "react-native";
import { useNavigation } from "@react-navigation/native";
import { handleSignout } from "../../services/firebase/firebaseConfig";
import firebase from "firebase";

const Profile = () => {
  const navigation = useNavigation();
  return (
    <View style={styles.container}>
      <Text>{firebase.auth().currentUser.email}</Text>

      <Pressable
        style={styles.button}
        onPress={() => {
         console.log('sign out')
        }}
      >
        <Text>sign out</Text>
      </Pressable>
    </View>
  );
};

export default Profile;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
  button: {
    position: "absolute",
    top: 25,
    backgroundColor: "#11DDAA",
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
    borderRadius: 15,
    height: 55,
    width: 55,
  },
});
```

This is shown when a user is authenticated. In the code above, `CurrentUser` is being used to get the currently signed in or authenticated user. In this case, it displays the email of the current user. 

The user can decide to sign out at any point and their should be a functionality that enables that the user signs out comfortably.

Going back to `Firebase.js` we add the functionality that enables the user to sign out just below the `handleSigIn` function.

**Handling user sign out**
```javascript
//handles user sign out
export const handleSignout = async () => {
  await firebase
    .auth()
    .signOut()
    .then(() => {
      console.log("Signed Out");
    })
    .catch((error) => {
      console.error(error);
    });
};
``` 
`handleSignout` function enables user to end authenticated sessions.

The `handleSignout` function is imported into `Home.js` where it the function call occurs. 

The user needs to sign out when the sign out button is pressed. Now, the button is updated to have the `handleSignout` function in it and also enable the user to navigate back to `Login.js`

```javascript
<Pressable
        style={styles.button}
        onPress={() => {
          handleSignout();
          navigation.navigate("SignInScreen");
          console.log("user signed out");
        }}
      >

```
In `Pressable` the `onPress` attribute is updated and the user can click the button to sign out of the application. The user is navigated to the sign in screen.  

---

## Observing Firebase user state

The user sessions need to be tracked in order to make the app even more efficient. There needs to be screens and components that need authentication to be accessed. If the user is not authenticated, the login screen is displayed, if the user is authenticated, the Profile screen is displayed.

`App.js` 

```javascript
import * as React from "react";
import firebase from "firebase";

import Profile from "./Profile"
import SignIn form "./SignIn"

export default function App() {
  const [user, setUser] = React.useState();

  React.useEffect(() => {
    firebase.auth().onAuthStateChanged((user) => {
      setUser(user);
    });
  }, []);

  const User = firebase.auth().currentUser;
  return <View>{User ? <Profile /> : <SignIn />}</View>;
}
```
The code snippet above is simply trying to explain that when the user is signed in, display the Home screen and when the user is signed out, display the Login screen. 

`onAuthstateChanged` observes for any change in the user state and updates the component.


## Conclusion

This article goes through a basic implementation of Firebase authentication. I believe with this, you can integrate Firebase authentication in a React-Native app. 

Firebase offers other authentication options like Google, Apple, Facebook and Phone authentications. In this article, we explored only the email and password method of authentication.

To learn more about Firebase and how to use it, visit the [Firebase](https://firebase.google.com/) website and you can check out the Firebase [documentation](https://firebase.google.com/docs).