Firebase Phone Auth with React Native Expo

Viewed 1952

So I have been trying to implement the firebase phone auth in my react native project. I followed this great tutorial linked below but was facing issues with changing the confirmation section to be in a different page instead of the phone number input and code input all being on the same page. I get an error stating the verificationId was not found as its being called in the previous page.

Tutorial Link

If anyone can help out out, that would be great.

Thanks

  const const Login  = () => {
  const navigation =useNavigation();
  const [phoneNumber, setPhoneNumber] = useState();

  const [verificationId, setVerificationId] = useState(null);
  const recaptchaVerifier = useRef(null);




    const sendVerification  = () => {
       try {
    const phoneProvider = new firebase.auth.PhoneAuthProvider();
    phoneProvider
   .verifyPhoneNumber(phoneNumber, recaptchaVerifier.current)
   .then(setVerificationId);
     } catch (error) {
   alert(error);
     }
     navigation.navigate('OTPScreen', { verificationId: 
   verificationId})


     };
    return(
   

OTP screen

const const OTPScreen  = () => {

const verificationId = props.route.params.verificationId
 const [code, setCode] = useState('');


const confirmCode = () => {
  const credential = 
  firebase.auth.PhoneAuthProvider.credential(
    verificationId,
    code
  );
  firebase
    .auth()
    .signInWithCredential(credential)
    .then((result) => {
      console.log(result); 
      navigation.navigate('Home')  
        
    });
    

    };
   return(
   
2 Answers

There are two possible solution I have implemented

  1. Pass your confirmation object as params to new screens and then use it for OTP confirmation.
  2. You can also save this confirmation object in global store like redux.

For solution 1

const [confirm, setConfirm] = useState(null);


  async function signInWithPhoneNumber(phoneNumber) {
    const confirmation = await auth().signInWithPhoneNumber(phoneNumber);
    setConfirm(confirmation);
  }

Then navigate to your otp screen as

navigation.navigate('otpScreen', {confirm: confirm})

On your otpScreen get the confirm object as params (use appropriate syntax for functional or class component, whatever you are using) Then

const confirm = props.route.params.confirm

async function confirmCode() {
    try {
      await confirm.confirm(code);
    } catch (error) {
      console.log('Invalid code.');
    }
  }

the full firebase phone authentication full code is
check in android

import * as React from "react";
import { Text, View, TextInput, Button, StyleSheet, TouchableOpacity, Platform } from "react-native";
import { FirebaseRecaptchaVerifierModal } from "expo-firebase-recaptcha";
import * as firebase from "firebase";
try {
  firebase.initializeApp({
    apiKey: 'AIzaSyApGoaZVtoVTYnftHSbT9l7nDmDVUYJYpU',
      authDomain: 'playground-d4e7b.firebaseapp.com',
      databaseURL: 'https://playground-d4e7b.firebaseio.com',
      projectId: 'playground-d4e7b',
      storageBucket: 'playground-d4e7b.appspot.com',
      messagingSenderId: '903405300293',
      appId: '1:903405300293:web:c55227a2b8064da05d112c',
  });
} catch (err) {
  // ignore app already initialized error in snack
}

export default function App() {
  const recaptchaVerifier = React.useRef(null);
  const [phoneNumber, setPhoneNumber] = React.useState();
  const [verificationId, setVerificationId] = React.useState();
  const [verificationCode, setVerificationCode] = React.useState();
  const firebaseConfig = firebase.apps.length ? firebase.app().options : undefined;
  const [message, showMessage] = React.useState((!firebaseConfig || Platform.OS === 'web')
    ? { text: "To get started, provide a valid firebase config in App.js and open this snack on an iOS or Android device."}
    : undefined);

  return (
    <View style={{ padding: 20, marginTop: 50 }}>
      <FirebaseRecaptchaVerifierModal
        ref={recaptchaVerifier}
        firebaseConfig={firebaseConfig}
      />
      <Text style={{ marginTop: 20 }}>Enter phone number</Text>
      <TextInput
        style={{ marginVertical: 10, fontSize: 17 }}
        placeholder="+1 999 999 9999"
        autoFocus
        autoCompleteType="tel"
        keyboardType="phone-pad"
        textContentType="telephoneNumber"
        onChangeText={(phoneNumber) => setPhoneNumber(phoneNumber)}
      />
      <Button
        title="Send Verification Code"
        disabled={!phoneNumber}
        onPress={async () => {
          // The FirebaseRecaptchaVerifierModal ref implements the
          // FirebaseAuthApplicationVerifier interface and can be
          // passed directly to `verifyPhoneNumber`.
          try {
            const phoneProvider = new firebase.auth.PhoneAuthProvider();
            const verificationId = await phoneProvider.verifyPhoneNumber(
              phoneNumber,
              recaptchaVerifier.current
            );
            setVerificationId(verificationId);
            showMessage({
              text: "Verification code has been sent to your phone.",
            });
          } catch (err) {
            showMessage({ text: `Error: ${err.message}`, color: "red" });
          }
        }}
      />
      <Text style={{ marginTop: 20 }}>Enter Verification code</Text>
      <TextInput
        style={{ marginVertical: 10, fontSize: 17 }}
        editable={!!verificationId}
        placeholder="123456"
        onChangeText={setVerificationCode}
      />
      <Button
        title="Confirm Verification Code"
        disabled={!verificationId}
        onPress={async () => {
          try {
            const credential = firebase.auth.PhoneAuthProvider.credential(
              verificationId,
              verificationCode
            );
            await firebase.auth().signInWithCredential(credential);
            showMessage({ text: "Phone authentication successful " });
          } catch (err) {
            showMessage({ text: `Error: ${err.message}`, color: "red" });
          }
        }}
      />
      {message ? (
        <TouchableOpacity
          style={[StyleSheet.absoluteFill, { backgroundColor: 0xffffffee, justifyContent: "center" }]}
          onPress={() => showMessage(undefined)}>
          <Text style={{color: message.color || "blue", fontSize: 17, textAlign: "center", margin: 20, }}>
            {message.text}
          </Text>
        </TouchableOpacity>
      ) : undefined}
    </View>
  );
}

Related