Implementing OTP Phone Authentication in React Native
Tags: reactnative, authentication, otp
Published: 2023-01-09 01:51:26

by [Joseph Chege](https://blog.openreplay.com/authors/joseph-chege)

Phone number-based auth is one of the many authentication strategies you can add to your applications. An OTP (one-time password) SMS verification minimizes spamming and fraud and can be used to verify logins automatically. This article will implement phone authentication using Firebase in a [React Native](https://reactnative.dev/) Expo application.

## Creating the Firebase App

Firebase provides several authentication providers, one of them being phone number-based authentication. To set this up:
- Navigate to your [Firebase console](https://console.firebase.google.com/) and **Add Project**.
- Provide the application name and **Create project**.
- Once the project creation process is done, add a new web application.

![Project dashboard](https://blog.openreplay.com/images/implementing-otp-phone-number-authentication-in-react-native/images/oLhYW6U.png)

Register the app to Add Firebase to your web app. Next, you will be presented with some guidelines for installing Firebase. Copy the Firebase configurations that use npm. You will use this code later in this guide to initialize a Firebase SDK to React Native.

![Firebase configurations](https://blog.openreplay.com/images/implementing-otp-phone-number-authentication-in-react-native/images/JHfYojI.png)

On your console dashboard, navigate to **authentication**, and **Get Started** with Firebase Auth by adding your first sign-in method. Select **Phone** as a native provider, enable it, and **Save**.

![Firebase Phone Number Authentication](https://blog.openreplay.com/images/implementing-otp-phone-number-authentication-in-react-native/images/zY09lMq.png)

![Firebase Phone Number Authentication](https://blog.openreplay.com/images/implementing-otp-phone-number-authentication-in-react-native/images/qEI59k3.png)


It's good to note that Phone Authentication requires additional configuration steps. Firebase Authentication signs in a user by sending an SMS message to the user's phone. This guide follows [Firebase Phone Number Authentication using JavaScript to set up the correct configuration steps for the Phone provider](https://firebase.google.com/docs/auth/web/phone-auth?authuser=0&hl=en) inside your React Native apps.

## Configuring React Native App

Navigate to the directory where you want your project to live and open a terminal that points to this directory. Run the following command to initialize an [Expo application](https://expo.dev/):

```
npx create-expo-app firebase-phone-auth
```

Once the installation is done, proceed to the newly created directory.

```
cd firebase-phone-auth
```

Install the following dependencies:

- For navigation:

```
npx expo install @react-navigation/native @react-navigation/stack react-native-safe-area-context react-native-gesture-handler
```

- Firebase SDK:

```
npx expo install firebase
```

- For Firebase reCAPTCHA verifier:

```
npx expo install expo-firebase-recaptcha react-native-webview
```

On the root directory, change the file `app.config.json` to `app.config.js*` and edit it as below:

```javascript
export default {
"expo": {
    "name": "fbphoneauth",
    "slug": "fbphoneauth",
    "version": "1.0.0",
    "orientation": "portrait",
    "icon": "./assets/icon.png",
    "userInterfaceStyle": "light",
    "splash": {
    "image": "./assets/splash.png",
    "resizeMode": "contain",
    "backgroundColor": "#ffffff"
    },
    "updates": {
    "fallbackToCacheTimeout": 0
    },
    "assetBundlePatterns": [
    "**/*"
    ],
    "ios": {
    "supportsTablet": true
    },
    "android": {
    "adaptiveIcon": {
        "foregroundImage": "./assets/adaptive-icon.png",
        "backgroundColor": "#FFFFFF"
    }
    },
    "web": {
    "favicon": "./assets/favicon.png"
    }
},
"extra" :{
    firebaseApiKey: your_firebase_api_key,
    firebaseAuthDomain: your_firebase_auth_domain,
    firebaseProjectId: your_firebase_project_id,
    firebaseStorageBucket: your_firebase_storage_bucket,
    firebaseMessagingSenderId: your_firebase_messaging_sender_id,
    firebaseAppId: your_firebase_app_id
}
}
```

In the above section, add Firebase code you copied earlier to the `extra` section. Ensure these Firebase configurations reflects based on the above-highlighted areas.

To connect to the Firebase SDK using the above configurations, create a `config` directory in the root folder. Inside the directory, create a `firebase.js` file:

```javascript
import config from '../app.config';

const firebaseConfig = {
    apiKey: config.extra.firebaseApiKey,
    authDomain: config.extra.firebaseAuthDomain,
    projectId: config.extra.firebaseProjectId,
    storageBucket: config.extra.firebaseStorageBucket,
    messagingSenderId: config.extra.firebaseMessagingSenderId,
    appId: config.extra.firebaseAppId
};

module.exports = firebaseConfig;
```

This way, React Native can communicate with your Firebase app.

## Creating a Home Screen

Let's create a screen to welcome the user and a Sign in button. On the project root directory, create a `screens` directory. Inside the directory, create a `Home.js` to display the home screen as follows:

- Import the necessary packages:

```javascript
import {View,Text,StyleSheet,Button} from 'react-native';
```

- The render function:

```javascript
const HomeScreen = ({navigation}) => {
    return (
        <View style={styles.container}>
            <Text style={styles.text}>Hurray!!, we are on the home screen</Text>
            <Button onPress={ () => navigation.navigate("SignIn")} title="Go to Sign In" />
        </View>
    )
}
```

- The styles:

```javascript
const styles = StyleSheet.create({
    text:{
        color: "#aaa"
    },
    container:{
        flex: 1,
        backgroundColor: '#fff',
        alignItems: 'center',
        justifyContent: 'center',
    }
});
```

- Export the render function by default:

```javascript
export default HomeScreen;
```

## Creating a Phone Sign-in Screen

Inside the `screens` directory, create `SignInScreen.js` files for creating the signing-in methods. Inside this file:

- Import the needed packages:

```javascript
import {View,Text,StyleSheet,TextInput,Button} from 'react-native';
import {React,useState,useRef} from 'react';
import {getApp,initializeApp} from 'firebase/app';
import {FirebaseRecaptchaVerifierModal,FirebaseRecaptchaBanner} from 'expo-firebase-recaptcha';
import {getAuth,PhoneAuthProvider,signInWithCredential} from 'firebase/auth';
import fbConfig from '../config/firebase';
```

- Initialize the Firebase SDK:

```javascript
try{
    firebase.initializeApp(fbConfig);
}catch(error){
    console.log("Initializing error ",error);
}
```

- Initialize an instance for the app and auth:

```javascript
const app = getApp();
const auth = getAuth(app);

if (!app?.options || Platform.OS === 'web') {
    throw new Error(
    'This example only works on Android or iOS, and requires a valid Firebase config.'
    );
}
```

In the render function:

- Define the state variables:

```javascript
const recaptchaVerifier = useRef(null);

const [phoneNumber,setPhoneNumber] = useState('');
const [verificationId,setVerificationID] = useState('');
const [verificationCode,setVerificationCode] = useState('');

const firebaseConfig = app ? app.options : undefined;
const [info,setInfo] = useState("");
const attemptInvisibleVerification = false;
```

This sets what we need in this application. First, you need the phoneNumber to carry authentication. A verificationId that sets the OTP code sent by Firebase via SMS and verificationCode that confirms and verifies the received verification code.

It's essential to remember that Firebase necessitates a reCAPTCHA verifier to avoid misuse, such as by making sure the request for a phone number verification comes from one of the authorized domains of your application. When using the Firebase SDK, you need to utilize the `recaptchaVerifier` object, and the reCAPTCHA will be generated automatically.

This guide will use the `FirebaseRecaptchaBanner` (a reCAPTCHA widget) that requires user interaction to complete authentication successfully. You can also use an [invisible reCAPTCHA](https://www.google.com/recaptcha/intro/invisible.html?authuser=0) to validate the user without requiring user action, in contrast to the reCAPTCHA widget.

- Define the function for sending the verification code:

```javascript
const handleSendVerificationCode = async () => {
    try{
        const phoneProvider = new PhoneAuthProvider(auth); // initialize the phone provider.
        const verificationId = await phoneProvider.verifyPhoneNumber(
            phoneNumber,
            recaptchaVerifier.current
        ); // get the verification id
        setVerificationID(verificationId); // set the verification id
        setInfo('Success : Verification code has been sent to your phone'); // If Ok, show message.
    }catch(error){
        setInfo(`Error : ${error.message}`); // show the error
    }
};
```

- Define the function for verifying the entered verification code:

```javascript
 const handleVerifyVerificationCode = async () => {
    try{
        const credential = PhoneAuthProvider.credential(verificationId,verificationCode); // get the credential
        await signInWithCredential(auth,credential); // verify the credential
        setInfo('Success: Phone authentication successful'); // if OK, set the message
        navigation.navigate("Welcome"); // navigate to the welcome screen
    }catch(error){
        setInfo(`Error : ${error.message}`); // show the error.
    }
}
```

- Render the phone number input fields and execute the above-created methods:

```jsx
return (
    <View style={styles.container}>

        <FirebaseRecaptchaVerifierModal 
            ref={recaptchaVerifier}
            firebaseConfig={firebaseConfig}
        />

        {
            info && <Text style={styles.text}>{info}</Text>
        }

        { // show the phone number input field when verification id is not set.
            !verificationId && (
                <View>
                    <Text style={styles.text}>Enter the phone number</Text>

                        <TextInput
                            placeholder='+2547000000'
                            autoFocus
                            autoCompleteType='tel'
                            keyboardType='phone-pad'
                            textContentType='telephoneNumber'
                            onChangeText={ (phoneNumber) => setPhoneNumber(phoneNumber)}
                        />

                        <Button 
                            onPress={ () => handleSendVerificationCode()}
                            title= "Send Verification Code"
                            disabled={!phoneNumber}
                        />
                </View>
            )
            
        }

        { // if verification id exists show the confirm code input field.
            verificationId && (
                <View>
                    <Text style={styles.text}>Enter the verification code</Text>

                    <TextInput
                        editable={!!verificationId}
                        placeholder= "123456"
                        onChangeText={setVerificationCode}
                    />

                    <Button
                        title= "Confirm Verification Code"
                        disabled={!verificationCode}
                        onPress = {() => handleVerifyVerificationCode()}
                    />
                </View>
            )
        }

        {attemptInvisibleVerification && <FirebaseRecaptchaBanner/>}
    </View>
)
```

- Define some styles:

```javascript
const styles = StyleSheet.create({
text:{
    color: "#aaa"
},
container:{
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
}
})
```

- Export the render function:

```javascript
export default SignInScreen;
```



<h2>Open Source Session Replay</h2> 

_<a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a> is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data._

![OpenReplay](https://blog.openreplay.com/banner-blog_1oYPGT.png)

_Start enjoying your debugging experience - <a href="https://github.com/openreplay/openreplay" >start using OpenReplay for free</a>._









## Creating the Authenticated Screen

If the user confirms the send code and Firebase verifies it, create a screen that will be triggered for successful authentication. Inside the `screens` directory create `Welcome.js` files for showing once logged in. Inside this file:

- Import the necessary packages:

```javascript
import {View,Text,StyleSheet} from 'react-native';
```

- Define the render function:

```javascript
const WelcomeScreen = () => {
return (
    <View style={styles.container}>
        <Text style={styles.text}>Hurray!!, we are on the welcome screen</Text>
    </View>
)
}
```

- Define the styles:

```javascript
const styles = StyleSheet.create({
text:{
    color: "#aaa"
},
container:{
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
}
})
```

- Export the render function:

```javascript
export default WelcomeScreen;
```

## Connecting up the Created Screens

Now that everything is set, use React navigation to control the application stack. Edit `App.js` as follows:

- Import the necessary packages:

```javascript
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
```

- Import the screens:

```javascript
import Home from './screens/Home';
import SignIn from './screens/SignInScreen';
import Welcome from './screens/Welcome';
```

- Define the stack:

```javascript
const Stack = createStackNavigator();
```

- Change the rendered content in the render function:

```javascript
export default function App() {
    return (
        <NavigationContainer>
        <Stack.Navigator initialRouteName='Home'>
            <Stack.Screen name="Home" component={Home} options={{title:"Welcome"}} />
            <Stack.Screen name="SignIn" component={SignIn} options={{title:"SignInScreen"}} />
            <Stack.Screen name="Welcome" component={Welcome} options={{title:"Welcome"}} />
        </Stack.Navigator>
        </NavigationContainer>
    );
}
```

## Running and Testing the App

Ensure your development is up and running with the following command to start the application:

```
### for android
npm run 
### for ios
npm run ios
```

Here is how the application Home screen will be launched on your device:

![Home screen](https://blog.openreplay.com/images/implementing-otp-phone-number-authentication-in-react-native/images/YLU0lgY.jpg)

Proceed to **GO TO SIGN IN** and provide a valid phone number as follows:

![Send verification code](https://blog.openreplay.com/images/implementing-otp-phone-number-authentication-in-react-native/images/JmZrSp7.jpg)

To verify your number, click **SEND VERIFICATION CODE**. This will launch the Firebase ReCAPTCHA banner:

![ReCAPTCHA banner](https://blog.openreplay.com/images/implementing-otp-phone-number-authentication-in-react-native/images/lRXwQcI.jpg)

Check that you're not a robot. A verification code will be sent to the provided phone number. Confirm the code.

![Firebase verification code](https://blog.openreplay.com/images/implementing-otp-phone-number-authentication-in-react-native/images/Sj0Ae96.jpg)

If everything was successful, a logged-in welcome screen should be on your device as such:

![Logged-in welcome screen](https://blog.openreplay.com/images/implementing-otp-phone-number-authentication-in-react-native/images/O77t8ns.jpg)

## Conclusion

This guide taught you how you set up Firebase Phone Authentication in a React Native app. I hope you found it helpful.

> A TIP FROM THE EDITOR: For another way of doing auth in React Native, check out [Google OAuth with Firebase in React Native](https://blog.openreplay.com/google-oauth-with-firebase-in-react-native/).


[![newsletter](https://blog.openreplay.com/newsletter_Z1P0UIP.png)](https://newsletter.openreplay.com/)