skip to Main Content

I am following the instruction described here to create accounts on firebase using email and password and then adding a phone number as 2FA for MFA. Now I want when the users login with their email and password on the frontend in react native to link their phoneNumber to their accounts. Reason for this is I want my users to login either with their phones or emails. Here is how I am doing this. I am basically trying to link accounts after OTP verification.

const onVerifyOtp = async (otp: string) => {
    try {
      setLoading(true);
      const credential = auth.PhoneAuthProvider.credential(verificationId, otp);
      const multiFactorAssertion =
        auth.PhoneMultiFactorGenerator.assertion(credential);

      // Complete sign in
      const userCredential = await resolve.resolveSignIn(multiFactorAssertion);

      if (userCredential.user) {
        // link the phone number to the authenticated user
        await auth().currentUser.linkWithCredential(credential);
      }

      const newuser = new UserInterface();
      newuser.id = userCredential.user?.uid || '';
      newuser.phoneNumber = userCredential.user?.phoneNumber || '';
      newuser.otpRequested = true;
      setLoading(false);
      setLogins(0);
      setUser(newuser);
      setUserData(newuser);
    } catch (err: any) {
      setError(invalidOtp);
      setLoading(false);
      logger.log(err);
    }
  }

Yet for some reason this is not working. Keeps on throwing the error.

Error: [auth/unsupported-first-factor] Enrolling a second factor or signing in with a multi-factor account requires sign-in with a supported first factor.

At the point i am trying to link the accounts, the user is already signed in so I am not sure why this error. Can anyone help me figure this out?

UPDATE
Here is the code responsible for creating user in Firebase. As you can see we are correctly adding 2FA and setting email to verified

const user = await firebase.auth().createUser({
        email,
        password,
        emailVerified: true,
        multiFactor: {
          enrolledFactors: [
            // Primary second factor
            {
              phoneNumber: phone,
              factorId: 'phone'
            }
          ]
        }
      });
[

2

Answers


  1. If you are using MFA it’s not possible to use Phone Number as a first login as the error states,

    Error: [auth/unknown] UNSUPPORTED_FIRST_FACTOR : A phone number cannot be set as a first factor on an SMS based MFA user.

    NativeFirebaseError: [auth/unknown] UNSUPPORTED_FIRST_FACTOR : A phone number cannot be set as a first factor on an SMS based MFA user.

    So you have two options (without custom auth provider):

    1. Use MFA (Multi-Factor Authentication) with email login.
    2. Disable MFA and use Email or Phone Number as a way to login.

    You can however handle this yourself with custom-provider which allows you (but also requires you) to take control of the auth flow yourself.

    Login or Signup to reply.
  2. The error you’re encountering, [auth/unsupported-first-factor] Enrolling a second factor or signing in with a multi-factor account requires sign-in with a supported first factor, occurs when you try to link a phone number as a second factor without signing in with the primary factor first.

    To resolve this issue, you need to ensure that the user has already signed in with the primary factor (in this case, their email and password) before attempting to link the phone number as a second factor.

    Here’s an updated approach to linking the phone number after successful OTP verification:

    const onVerifyOtp = async (otp: string) => {
      try {
        setLoading(true);
        const credential = auth.PhoneAuthProvider.credential(verificationId, otp);
        const multiFactorAssertion = auth.PhoneMultiFactorGenerator.assertion(credential);
    
        // Complete sign in with the primary factor (email and password)
        const userCredential = await auth().signInWithEmailAndPassword(email, password);
    
        if (userCredential.user) {
          // link the phone number to the authenticated user
          await userCredential.user.linkWithCredential(credential);
        }
    
        const newuser = new UserInterface();
        newuser.id = userCredential.user?.uid || '';
        newuser.phoneNumber = userCredential.user?.phoneNumber || '';
        newuser.otpRequested = true;
        setLoading(false);
        setLogins(0);
        setUser(newuser);
        setUserData(newuser);
      } catch (err: any) {
        setError(invalidOtp);
        setLoading(false);
        logger.log(err);
      }
    };
    

    In the updated code, we first sign in the user with their email and password using signInWithEmailAndPassword(). This ensures that the primary factor is established before attempting to link the phone number as a second factor. Then, we use linkWithCredential() on the userCredential.user object to link the phone number to the authenticated user.

    Make sure to replace email and password with the appropriate variables containing the user’s email and password.

    By following this approach, you should be able to link the phone number to the user’s account after OTP verification without encountering the "unsupported-first-factor" error.
    Reference: https://firebase.google.com/docs/auth/web/account-linking

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search