Phone Number Authentication in React Native with Firebase

by Didin J. on Jun 11, 2025 Phone Number Authentication in React Native with Firebase

Learn how to implement phone number authentication in React Native using Firebase, with OTP verification, session handling, and emulator testing.

Phone number authentication has become a popular and convenient method for verifying users in mobile applications. Unlike traditional email and password logins, phone authentication simplifies the process by removing the need for users to remember passwords. Instead, users authenticate via a one-time password (OTP) sent directly to their mobile device.

Firebase, a comprehensive backend platform from Google, offers a robust and easy-to-implement phone authentication system. With just a few lines of code, developers can integrate secure OTP verification and user session handling into their React Native apps, without managing their backend infrastructure.

In this article, we’ll walk you through implementing phone number authentication in a React Native application using Firebase. Whether you’re building a social app, an e-commerce platform, or a user portal, this feature ensures a frictionless and secure sign-in experience for your users.

  • By the end of this tutorial, you’ll have:
  • Set up Firebase and enable phone authentication.
  • Built a phone number input and OTP verification screen.
  • Authenticated users securely and handled errors gracefully.


Step 1: Setting Up the Firebase Project

Before integrating Firebase phone authentication into your React Native app, you need to set up a Firebase project and configure it for phone sign-in.

1.1 Create a Firebase Project

  1. Go to the Firebase Console.
  2. Click "Add Project", give it a name (e.g., ReactNativePhoneAuth), and follow the setup wizard.
  3. You can disable Google Analytics for this project unless you plan to use it.

1.2 Register Your App

After your project is created:

  • Click "Add app" and choose the platform (Android or iOS, or both).
  • Enter your app’s package name:
    •   For Android: Found in android/app/src/main/AndroidManifest.xml under the package.
    •   For iOS: Found in Xcode under the project settings as Bundle Identifier.

Follow the steps to download the configuration files:

  • google-services.json for Android
  • GoogleService-Info.plist for iOS

Place them into the appropriate directories:

  • Android: Place google-services.json in android/app/
  • iOS: Place GoogleService-Info.plist in iOS/ using Xcode (drag and drop into the project navigator)

1.3 Enable Phone Authentication

  1. In the Firebase Console, navigate to Build → Authentication → Sign-in method.
  2. Enable Phone as a sign-in provider.
  3. Optionally, add test phone numbers (for testing without sending actual SMS during development).

1.4 (Optional) Configure Firestore or Realtime Database

If you plan to store user data, such as names or roles, configure a database:

  • Navigate to Build → Firestore Database or Realtime Database.
  • Click Create database and select your rules (you can start in test mode for development).


Step 2: Creating and Preparing the React Native Project

Before adding Firebase packages, we need to create a new React Native project using the React Native CLI.

2.1 Create a New React Native Project

In your terminal, run:

npx @react-native-community/cli init ReactNativePhoneAuth

This command creates a new directory named ReactNativePhoneAuth with all the necessary files and folders.

Then navigate to your project:

cd ReactNativePhoneAuth

2.2 Install Firebase Packages

Now install the Firebase modules:

npm install @react-native-firebase/app @react-native-firebase/auth

2.3 Configure Android and iOS (Quick Recap)

For Android:

  • Place google-services.json in android/app/.
  • Update android/build.gradle and android/app/build.gradle as explained earlier.
  • Apply the Google services plugin and check minSdkVersion.

For iOS:

  • Place GoogleService-Info.plist in Xcode under your project target.
  • Install CocoaPods:
cd ios && pod install && cd ..

Make sure your iOS deployment target is 11.0 or higher.


Step 3: Configuring Firebase with React Native

Now that your React Native project is set up and Firebase packages are installed, it's time to integrate Firebase into your Android and iOS builds.

3.1 Android Configuration

a. Add Firebase Config File

  1. Download google-services.json from your Firebase Console.
  2. Place it in your React Native project at: android/app/google-services.json

b. Modify android/build.gradle

Open android/build.gradle and ensure the following:

buildscript {
    dependencies {
        ...
        classpath("com.google.gms:google-services:4.3.15")
    }
}

Also, make sure your minSdkVersion is at least 24:

ext {
    minSdkVersion = 24
}

c. Modify android/app/build.gradle

At the top of the file, apply the Google Services plugin after other plugins:

apply plugin: "com.google.gms.google-services"

Also, ensure your dependencies section includes Firebase Auth:

dependencies {
    ...
    implementation("com.google.firebase:firebase-auth")

    ...
}

You don’t need to manually add firebase-auth if you're using @react-native-firebase/auth, but it’s good to double-check for native linking.

3.2 iOS Configuration

a. Add Firebase Config File

  1. Download GoogleService-Info.plist from your Firebase Console.
  2. Open your project in Xcode (iOS/PhoneAuthApp.xcworkspace).
  3. Right-click on the root project in the project navigator.
  4. Select "Add Files to..." and add the GoogleService-Info.plist file.
  5. Ensure “Copy items if needed” is checked.

b. Install CocoaPods

Navigate to the iOS directory and install pods:

cd ios
pod install
cd ..

Make sure your iOS deployment target is set as the default in ios/Podfile:

platform :ios, min_ios_version_supported

Also, enable Hermes.

  use_react_native!(
    :path => config[:reactNativePath],
    :hermes_enabled => true,
    # An absolute path to your application root.
    :app_path => "#{Pod::Config.instance.installation_root}/.."
  )

Firebase Is Now Configured

You now have Firebase integrated into your Android and iOS builds. The Firebase SDK is ready to use, and phone authentication can be initiated using the Firebase Auth module.


Step 4: Implementing Phone Authentication UI

To create a smooth phone sign-in experience, we’ll build two screens:

  1. PhoneInputScreen – user enters their phone number.
  2. OTPScreen – user enters the verification code (OTP) they receive via SMS.

4.1 Set Up Navigation

We’ll use React Navigation to move between screens.

Install React Navigation packages

npm install @react-navigation/native
npm install react-native-screens react-native-safe-area-context react-native-gesture-handler react-native-reanimated
npm install @react-navigation/native-stack

⚠️ Don’t forget to wrap your app in a NavigationContainer.

In App.js:

import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';

import PhoneInputScreen from './screens/PhoneInputScreen';
import OTPScreen from './screens/OTPScreen';

const Stack = createNativeStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="PhoneInput">
        <Stack.Screen name="PhoneInput" component={PhoneInputScreen} />
        <Stack.Screen name="OTPScreen" component={OTPScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

4.2 PhoneInputScreen – Entering the Phone Number

Create screens/PhoneInputScreen.js:

import React, { useState } from 'react';
import { View, TextInput, Button, Alert, StyleSheet } from 'react-native';
import auth from '@react-native-firebase/auth';

export default function PhoneInputScreen({ navigation }) {
  const [phoneNumber, setPhoneNumber] = useState('');

  const sendVerification = async () => {
    if (!phoneNumber) {
      Alert.alert('Error', 'Please enter a valid phone number.');
      return;
    }

    try {
      const confirmation = await auth().signInWithPhoneNumber(phoneNumber);
      navigation.navigate('OTPScreen', { confirmation });
    } catch (error) {
      Alert.alert('SMS Error', error.message);
    }
  };

  return (
    <View style={styles.container}>
      <TextInput
        placeholder="+1 123 456 7890"
        keyboardType="phone-pad"
        style={styles.input}
        value={phoneNumber}
        onChangeText={setPhoneNumber}
      />
      <Button title="Send OTP" onPress={sendVerification} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 24,
    justifyContent: 'center',
  },
  input: {
    borderBottomWidth: 1,
    marginBottom: 16,
    fontSize: 18,
    paddingVertical: 8,
  },
});

4.3 OTPScreen – Verifying the OTP

This screen lets users enter the OTP they received and verifies it using the Firebase confirmation object passed from the previous screen.

Create screens/OTPScreen.js:

import React, { useState } from 'react';
import { View, TextInput, Button, Alert, StyleSheet, Text } from 'react-native';

export default function OTPScreen({ route, navigation }) {
  const [code, setCode] = useState('');
  const { confirmation } = route.params;

  const confirmCode = async () => {
    if (!code) {
      Alert.alert('Error', 'Please enter the OTP.');
      return;
    }

    try {
      await confirmation.confirm(code);
      Alert.alert('Success', 'Phone number verified!');
      // Navigate to home/dashboard screen or reset the stack
      // navigation.reset({ index: 0, routes: [{ name: 'Home' }] });
    } catch (error) {
      Alert.alert('Invalid Code', 'The OTP you entered is incorrect.');
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.label}>Enter OTP:</Text>
      <TextInput
        placeholder="123456"
        keyboardType="number-pad"
        style={styles.input}
        value={code}
        onChangeText={setCode}
        maxLength={6}
      />
      <Button title="Verify OTP" onPress={confirmCode} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 24,
    justifyContent: 'center',
  },
  label: {
    fontSize: 16,
    marginBottom: 8,
  },
  input: {
    borderBottomWidth: 1,
    fontSize: 18,
    marginBottom: 16,
    paddingVertical: 8,
  },
});

At this point, your authentication flow works as follows:

  1. The user enters a phone number.
  2. Firebase sends an OTP.
  3. The user enters the OTP.
  4. Firebase verifies the code and signs the user in.

Firebase manages user sessions automatically, so you can check auth().currentUser to see if someone is logged in.


Step 5: Handling Auth State and Session Persistence

Firebase automatically persists the authenticated user session. However, your app still needs to detect that state and route users accordingly.

We’ll:

  • Listen to authentication state changes.
  • Redirect authenticated users to a "Home" screen.
  • Prevent showing the sign-in flow again unless the user logs out.

5.1 Create a Home Screen

Let’s make a simple screen for logged-in users.

screens/HomeScreen.js:

import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import auth from '@react-native-firebase/auth';

export default function HomeScreen({ navigation }) {
  const handleLogout = async () => {
    await auth().signOut();
    navigation.reset({ index: 0, routes: [{ name: 'PhoneInput' }] });
  };

  return (
    <View style={styles.container}>
      <Text style={styles.welcome}>Welcome, {auth().currentUser?.phoneNumber}!</Text>
      <Button title="Logout" onPress={handleLogout} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  welcome: { fontSize: 18, marginBottom: 16 },
});

5.2 Detect Auth State in App.js

We’ll now modify App.js to conditionally show either:

  • Auth flow (PhoneInputScreen, OTPScreen)
  • Or the HomeScreen if the user is already signed in

Update App.js:

import React, {useEffect, useState} from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import auth, {FirebaseAuthTypes} from '@react-native-firebase/auth';

import PhoneInputScreen from './screens/PhoneInputScreen';
import OTPScreen from './screens/OTPScreen';
import HomeScreen from './screens/HomeScreen';

const Stack = createNativeStackNavigator();

export default function App() {
  const [initializing, setInitializing] = useState(true);
  const [user, setUser] = useState<FirebaseAuthTypes.User | null>(null);

  useEffect(() => {
    const unsubscribe = auth().onAuthStateChanged(user => {
      setUser(user);
      if (initializing) setInitializing(false);
    });

    return unsubscribe;
  }, []);

  if (initializing) return null; // or a splash screen

  return (
    <NavigationContainer>
      <Stack.Navigator screenOptions={{headerShown: false}}>
        {user ? (
          <Stack.Screen name="Home" component={HomeScreen} />
        ) : (
          <>
            <Stack.Screen name="PhoneInput" component={PhoneInputScreen} />
            <Stack.Screen name="OTPScreen" component={OTPScreen} />
          </>
        )}
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Now Your App Supports:

  • Session persistence
  • Auto-login if the user is already authenticated
  • Logout and redirection to the phone input screen


Step 6: Testing Phone Authentication with Firebase Emulator or Live Numbers

When building phone authentication, testing with real SMS every time can be slow, expensive, and risky. Thankfully, Firebase provides two excellent solutions:

  • Test phone numbers (for production projects)
  • Firebase Auth Emulator (for local development)

6.1 Option 1: Use Firebase Test Phone Numbers

Firebase lets you predefine test numbers and codes — no actual SMS is sent.

How to Set Up:

  1. Go to the Firebase Console.
  2. Navigate to Authentication > Sign-in method > Phone.
  3. Scroll down to the Phone numbers for testing.
  4. Add test entries like:
Phone Number Verification Code
+15555550100 123456

How to Use:

When testing, enter the test number and input the predefined OTP code — Firebase will automatically verify it without sending an SMS.

🔐 These numbers only work in debug builds or from whitelisted environments. They won't work for users in production.

6.2 Option 2: Use Firebase Emulator for Local Development

The Firebase Auth Emulator allows full offline testing with no real network calls.

Setup Instructions:

1. Install the Firebase CLI (if you haven’t):

npm install -g firebase-tools

2. Initialize the emulator in your project root:

firebase init emulators

  • Choose Authentication.
  • Set a port (e.g., 9099).

3. Start the emulator:

firebase emulators:start

4. In your app, connect the Firebase Auth module to the emulator:

if (__DEV__) {
  auth().useEmulator('http://localhost:9099');
}

5. You can now test phone numbers locally and even create mock accounts via the Emulator UI at http://localhost:4000 (if enabled).

Phone Number Authentication in React Native with Firebase - app

Caveats to Remember

  • Repeated use of real numbers may trigger rate limiting or reCAPTCHA errors.
  • Avoid using personal numbers during development — use the test suite or emulator.
  • Firebase does not allow sending OTPs to some non-mobile VoIP numbers.


Final Thoughts

You’ve now built a complete phone number authentication flow in React Native using Firebase:

  • UI to input phone and OTP
  • Firebase Auth integration
  • Session handling
  • Testing with test numbers or an emulator

You can get the full source code on our GitHub.

That's just the basics. If you need more deep learning about React.js, React Native, or related, you can take the following cheap course:

Thanks!