Jump to top

Multi-factor Auth

Increase security by adding Multi-factor authentication to your app.

Before a user can enroll a second factor they need to verify their email. See User interface is returned.

TOTP MFA

The official guide for Firebase web TOTP authentication explains the TOTP process well, including project prerequisites to enable the feature, as well as code examples.

The API details and usage examples may be combined with the full Phone auth example below to give you an MFA solution that fully supports TOTP or SMS MFA.

You may also find it useful to investigate the local / manual test screens that we use to verify this functionality.

Phone MFA

iOS Setup

Make sure to follow the official Identity Platform documentation to enable multi-factor authentication for your project and verify your app.

Enroll a new factor

Begin by obtaining a MultiFactorUser instance for the current user. This is the entry point for most multi-factor operations:

import {
  PhoneAuthProvider,
  PhoneMultiFactorGenerator,
  getAuth,
  multiFactor,
} from '@react-native-firebase/auth';

const multiFactorUser = await multiFactor(getAuth().currentUser);

Request the session identifier and use the phone number obtained from the user to send a verification code:

const session = await multiFactorUser.getSession();
const phoneOptions = {
  phoneNumber,
  session,
};

// Sends a text message to the user
const verificationId = await new PhoneAuthProvider(getAuth()).verifyPhoneNumber(phoneOptions);

Once the user has provided the verification code received by text message, you can complete the process:

const cred = PhoneAuthProvider.credential(verificationId, verificationCode);
const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);
await multiFactorUser.enroll(multiFactorAssertion, 'Optional display name for the user');

You can inspect User#multiFactor for information about the user's enrolled factors.

Sign-in flow using phone multi-factor

Ensure the account has already enrolled a second factor. Begin by calling the default sign-in methods, for example email and password. If the account requires a second factor to complete login, an exception will be raised:

import {
  PhoneAuthProvider,
  PhoneMultiFactorGenerator,
  getAuth,
  signInWithEmailAndPassword,
  getMultiFactorResolver,
} from '@react-native-firebase/auth';

signInWithEmailAndPassword(getAuth(), email, password)
  .then(() => {
    // User has not enrolled a second factor
  })
  .catch(error => {
    const { code } = error;
    // Make sure to check if multi factor authentication is required
    if (code === 'auth/multi-factor-auth-required') {
      return;
    }

    // Other error
  });

Using the error object you can obtain a MultiFactorResolver instance and continue the flow:

const resolver = getMultiFactorResolver(getAuth(), error);

The resolver object has all the required information to prompt the user for a specific factor:

if (resolver.hints.length > 1) {
  // Use resolver.hints to display a list of second factors to the user
}

if (resolver.hints[0].factorId === PhoneMultiFactorGenerator.FACTOR_ID) {
  // Continue with the sign-in flow
}

Using a multi-factor hint and the session information you can send a verification code to the user:

const hint = resolver.hints[0];
const sessionId = resolver.session;

new PhoneAuthProvider(getAuth())
  .verifyPhoneNumber(hint, sessionId) // triggers the message to the user
  .then(verificationId => setVerificationId(verificationId));

Once the user has entered the verification code you can create a multi-factor assertion and finish the flow:

const credential = PhoneAuthProvider.credential(verificationId, verificationCode);

const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(credential);

resolver.resolveSignIn(multiFactorAssertion).then(userCredential => {
  // additionally onAuthStateChanged will be triggered as well
});

Upon successful sign-in, any onAuthStateChanged listeners will trigger with the new authentication state of the user.

To put the example together:

import {
  PhoneAuthProvider,
  PhoneMultiFactorGenerator,
  getAuth,
  signInWithEmailAndPassword,
  getMultiFactorResolver,
} from '@react-native-firebase/auth';

signInWithEmailAndPassword(getAuth(), email, password)
  .then(() => {
    // User has not enrolled a second factor
  })
  .catch(error => {
    const { code } = error;
    // Make sure to check if multi factor authentication is required
    if (code === 'auth/multi-factor-auth-required') {
      const resolver = getMultiFactorResolver(error);

      if (resolver.hints.length > 1) {
        // Use resolver.hints to display a list of second factors to the user
      }

      if (resolver.hints[0].factorId === PhoneMultiFactorGenerator.FACTOR_ID) {
        const hint = resolver.hints[0];

        new PhoneAuthProvider(getAuth())
          .verifyPhoneNumber({ multiFactorHint: hint, session: resolver.session }) // triggers the message to the user
          .then(verificationId => setVerificationId(verificationId));

        // Request verificationCode from user

        const credential = PhoneAuthProvider.credential(verificationId, verificationCode);

        const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(credential);

        resolver.resolveSignIn(multiFactorAssertion).then(userCredential => {
          // additionally onAuthStateChanged will be triggered as well
        });
      }
    }
  });

Testing

You can define test phone numbers and corresponding verification codes. The officialofficial guide contains more information on setting this up.