Implement Firebase Phone Authentication in React Native Apps

2019-12-03

Phone authentication allows the user to sign in using their phone number. This could be done traditionally by associating a password and storing it when the user first registers with the app. However, another common pattern to log in a user using their phone number is by sending a verification code in their registered mobile number. This verification code is a unique number and the user is only allowed to sign in when it matches.

In this tutorial, let us try creating a small login screen using a Phone authentication. To quickly and efficiently establish a backend service, let us use good old Firebase with a React Native app.

Table of Contents

  • Requirements
  • Generate a new project
  • Enable Phone Authentication
  • Create PhoneAuthScreen component
  • Add a method to send an OTP
  • Add OTP confirmation view
  • Running the app
  • Conclusion

Requirements/Stack

  • Node.js >= 10.x.x version installed
  • watchman
  • react-native-cli
  • Active Firebase project
  • react-native-firebase

Do note that, I am going to use an iOS simulator. So any library (such as react-native-firebase) that needs configuration set up to be platform-specific, please refer to their official docs.

If you are not familiar with how to set up a new Firebase project, please follow the instructions under Create a Firebase Project from a previous post.

Generate a new project

Create a new React Native app by executing the following command in a terminal window.

1react-native init rnPhoneAuthDemo
2
3# install following dependencies
4yarn add react-native-firebase

Enable Phone Authentication

To use Firebase SDK in React Native apps, you have to add the config file to your app. From Firebase console, click on Settings icon and go to Project settings.

ss2

At this web page, click on the button Add app select the platform and follow the instructions that are mentioned.

ss3

Download the file GoogleService-info.plist if you selected platform in the previous step is iOS. Then, open XCode add this file to the project.

ss4

For android users, you will download google-services.json and save it at the location android/app/.

After adding the config file, you will have to follow the instructions at react-native-firebase documentation here. Do not forget to configure Firebase/Auth dependency from the docs here.

To use phone authentication as a sign-in method, you have to enable it in the Firebase project. From Firebase console, go to Authentication > Sign-in method tab. There, enable the Phone authentication method.

ss5

ss6

The React Native app is going to use reCAPTCHA verification to verify a user. To set up this, open the file [PROJECT_NAME]/ios/[PROJECT_NAME].xworkspace in Xcode. Double-click the project name in the left tree view and select the app from the TARGETS section. Then select the Info tab, and expand the URL Types section.

Click the + button, and add a URL scheme for your reversed client ID. To find this value, open the GoogleService-Info.plist configuration file, and look for the REVERSED_CLIENT_ID key. Copy the value of that key, and paste it into the URL Schemes box on the configuration page. Leave the other fields blank.

ss7

That's it for all configuration and setups.

Create PhoneAuthScreen component

Phone authentication follows a particular flow to sign-in the user. It starts by a user entering their number and requests an OTP from the Firebase. The Firebase uses reCAPTCHA first, to verify the user's authenticity. Then, once that is confirmed, it sends the OTP to the mobile number ad user can enter that value to sign in successfully, if the OTP entered matches.

To start this process, first, let us import all the necessary statements for the PhoneAuthScreen component.

1import React, { Component } from 'react'
2import {
3 StyleSheet,
4 SafeAreaView,
5 TouchableOpacity,
6 View,
7 Text,
8 TextInput
9} from 'react-native'
10import firebase from 'react-native-firebase'

Create a class component with an initial state object. When the user enters the detail following variables have to be tracked.

  • phone: user's phone number.
  • verificationCode: OTP code sends by Firebase via SMS (by default).
  • confirmResult: when the verification code is received, Firebase provides a parameter confirmResult that you can manually save to confirm the code and proceed further.
  • userId: The unique identifier creates by Firebase on when a new user registers with the app.
1class PhoneAuthScreen extends Component {
2 state = {
3 phone: '',
4 confirmResult: null,
5 verificationCode: '',
6 userId: ''
7 }
8
9 // ...
10}
11
12export default PhoneAuthScreen

Method to send an OTP

Using a RegExp pattern, you can match the phone number against a pattern manually. If the phone number entered by the user in the input field matches the RegExp pattern, return a boolean true from this method. JavaScript's .test() the method is to match a string and it returns true if the phone number entered is valid.

Add the utility method validatePhoneNumber.

1validatePhoneNumber = () => {
2 var regexp = /^\+[0-9]?()[0-9](\s|\S)(\d[0-9]{8,16})$/
3 return regexp.test(this.state.phone)
4}

This method is used inside the handler method that contains logic to send the OTP to the user on the phone number entered. Create a handler method handleSendCode. Inside this method, using firebase.auth().signInWithPhoneNumber() is used. At this step, Firebase uses reCAPTCHA for the user to be verified as a "human". If the reCAPTCHA verification process is a success, this Firebase method has a promise attached to it that gets resolved.

1handleSendCode = () => {
2 // Request to send OTP
3 if (this.validatePhoneNumber()) {
4 firebase
5 .auth()
6 .signInWithPhoneNumber(this.state.phone)
7 .then(confirmResult => {
8 this.setState({ confirmResult })
9 })
10 .catch(error => {
11 alert(error.message)
12
13 console.log(error)
14 })
15 } else {
16 alert('Invalid Phone Number')
17 }
18}

When the promise resolves, it saves updates the state variable confirmResult.

Add OTP confirmation view

In this section, you are going to add the view when the user has received the verification code. The app at this point will display two input fields. One, for the user to change their phone number if there has been a mistake. Otherwise, the phone number is displayed from the initial screen and the user has to enter the OTP.

The method changePhoneNumber is going to take care of incorrect phone numbers and the handler method handleVerifyCode is going to send the request back to the Firebase to verify the OTP entered by the user. If the OTP verification approves, for now, you can display the user's uid in an alert message.

1this.setState({ confirmResult: null, verificationCode: '' })
2 }
3
4 handleVerifyCode = () => {
5 // Request for OTP verification
6 const { confirmResult, verificationCode } = this.state
7 if (verificationCode.length == 6) {
8 confirmResult
9 .confirm(verificationCode)
10 .then(user => {
11 this.setState({ userId: user.uid })
12 alert(`Verified! ${user.uid}`)
13 })
14 .catch(error => {
15 alert(error.message)
16 console.log(error)
17 })
18 } else {
19 alert('Please enter a 6 digit OTP code.')
20 }
21 }
22 renderConfirmationCodeView = () => {
23 return (
24 <View style={styles.verificationView}>
25 <TextInput
26 style={styles.textInput}
27 placeholder='Verification code'
28 placeholderTextColor='#eee'
29 value={this.state.verificationCode}
30 keyboardType='numeric'
31 onChangeText={verificationCode => {
32 this.setState({ verificationCode })
33 }}
34 maxLength={6}
35 />
36 <TouchableOpacity
37 style={[styles.themeButton, { marginTop: 20 }]}
38 onPress={this.handleVerifyCode}>
39 <Text style={styles.themeButtonTitle}>Verify Code</Text>
40 </TouchableOpacity>
41 </View>
42 )
43 }

Lastly, add the render method with the following JSX snippet:

1render() {
2 return (
3 <SafeAreaView style={[styles.container, { backgroundColor: '#333' }]}>
4 <View style={styles.page}>
5 <TextInput
6 style={styles.textInput}
7 placeholder='Phone Number with country code'
8 placeholderTextColor='#eee'
9 keyboardType='phone-pad'
10 value={this.state.phone}
11 onChangeText={phone => {
12 this.setState({ phone })
13 }}
14 maxLength={15}
15 editable={this.state.confirmResult ? false : true}
16 />
17
18 <TouchableOpacity
19 style={[styles.themeButton, { marginTop: 20 }]}
20 onPress={
21 this.state.confirmResult
22 ? this.changePhoneNumber
23 : this.handleSendCode
24 }>
25 <Text style={styles.themeButtonTitle}>
26 {this.state.confirmResult ? 'Change Phone Number' : 'Send Code'}
27 </Text>
28 </TouchableOpacity>
29
30 {this.state.confirmResult ? this.renderConfirmationCodeView() : null}
31 </View>
32 </SafeAreaView>
33 )
34 }

Also, do not forget to add some styling to the above components.

1const styles = StyleSheet.create({
2 container: {
3 flex: 1,
4 backgroundColor: '#aaa'
5 },
6 page: {
7 flex: 1,
8 alignItems: 'center',
9 justifyContent: 'center'
10 },
11 textInput: {
12 marginTop: 20,
13 width: '90%',
14 height: 40,
15 borderColor: '#555',
16 borderWidth: 2,
17 borderRadius: 5,
18 paddingLeft: 10,
19 color: '#fff',
20 fontSize: 16
21 },
22 themeButton: {
23 width: '90%',
24 height: 50,
25 alignItems: 'center',
26 justifyContent: 'center',
27 backgroundColor: '#888',
28 borderColor: '#555',
29 borderWidth: 2,
30 borderRadius: 5
31 },
32 themeButtonTitle: {
33 fontSize: 24,
34 fontWeight: 'bold',
35 color: '#fff'
36 },
37 verificationView: {
38 width: '100%',
39 alignItems: 'center',
40 marginTop: 50
41 }
42})

Running the app

Open the app in a simulator. Initially, the user will be welcomed by the following screen. Enter the phone number.

ss8

On clicking the button Send code, reCAPTCHA process is going to trigger if the user is signing-in for the first time.

ss9

After that, the user receives the verification code via SMS.

ss10

Enter the verification code.

ss11

On success, it responds with a uid in an alert message that you can verify in the Firebase console.

ss12

ss13

Conclusion

Congratulations! You have learned how to integrate the Phone auth process using Firebase SDK in a React Native application.

You can find the complete source code at this Github repo.

Originally published at Heartbeat.Fritz.AI

I'm Aman working as an independent fullstack developer with technologies such as Node.js, ReactJS, and React Native. I try to document and write tutorials to help JavaScript, Web and Mobile developers.