إضافة مصادقة متعدّدة العوامل إلى تطبيق الويب

إذا كنت قد أجريت ترقية إلى Firebase Authentication with Identity Platform، يمكنك إضافة ميزة "المصادقة المتعدّدة العوامل" عبر الرسائل القصيرة إلى تطبيق الويب.

تزيد ميزة "المصادقة المتعدّدة العوامل" من أمان تطبيقك. وفي حين أنّ المهاجمين غالبًا ما يعرّضون كلمات المرور والحسابات على وسائل التواصل الاجتماعي للخطر، يكون اعتراض الرسائل النصية أكثر صعوبة.

قبل البدء

  1. فعِّل مزود خدمة واحدًا على الأقل يتيح ميزة "المصادقة المتعدّدة العوامل". تتيح جميع مزودي الخدمة ميزة "المصادقة المتعدّدة العوامل"، باستثناء ميزة "المصادقة عبر الهاتف" و"المصادقة المجهولة" وApple Game Center.

  2. فعِّل المناطق التي تخطط لاستخدام ميزة "المصادقة عبر الرسائل القصيرة" فيها. Firebase تستخدم سياسة مناطق الرسائل القصيرة التي تحظر بشكل كامل، ما يساعد في إنشاء مشاريعك في حالة أكثر أمانًا تلقائيًا.

  3. تأكَّد من أنّ تطبيقك يتحقّق من عناوين البريد الإلكتروني للمستخدمين. تتطلب ميزة "المصادقة المتعدّدة العوامل" التحقّق من عنوان البريد الإلكتروني. يمنع ذلك الجهات الضارة من التسجيل في خدمة باستخدام عنوان بريد إلكتروني لا تملكه، ثم حظر المالك الحقيقي من خلال إضافة عامل ثانٍ.

استخدام ميزة "تعدد المستأجرين"

إذا كنت بصدد تفعيل ميزة "المصادقة المتعدّدة العوامل" لاستخدامها في بيئة متعددة المستأجرين، احرص على إكمال الخطوات التالية (بالإضافة إلى بقية التعليمات الواردة في هذا المستند):

  1. في Google Cloud Console، اختَر المستأجر الذي تريد العمل معه.

  2. في الرمز البرمجي، اضبط حقل tenantId في مثيل Auth على رقم تعريف المستأجر. على سبيل المثال:

    Web

    import { getAuth } from "firebase/auth";
    
    const auth = getAuth(app);
    auth.tenantId = "myTenantId1";
    

    Web

    firebase.auth().tenantId = 'myTenantId1';
    

تفعيل ميزة "المصادقة المتعدّدة العوامل"

  1. افتح صفحة المصادقة > طريقة تسجيل الدخول في Firebase Console.

  2. في قسم الإعدادات المتقدّمة ، فعِّل ميزة "المصادقة المتعدّدة العوامل" عبر الرسائل القصيرة.

    عليك أيضًا إدخال أرقام الهواتف التي ستختبر تطبيقك بها. على الرغم من أنّ تسجيل أرقام هواتف الاختبار هو إجراء اختياري، ننصحك بشدة بتسجيلها لتجنُّب تقييد المعدّل أثناء التطوير.

  3. إذا لم يسبق لك تفويض نطاق تطبيقك، أضِفه إلى القائمة المسموح بها في صفحة المصادقة > الإعدادات في Firebase Console.

اختيار نمط التسجيل

يمكنك اختيار ما إذا كان تطبيقك يتطلب ميزة "المصادقة المتعدّدة العوامل"، وكيفية تسجيل المستخدمين ومتى يتم ذلك. في ما يلي بعض الأنماط الشائعة:

  • تسجيل العامل الثاني للمستخدم كجزء من عملية التسجيل. استخدِم هذه الطريقة إذا كان تطبيقك يتطلب ميزة "المصادقة المتعدّدة العوامل" لجميع المستخدمين.

  • توفير خيار قابل للتخطّي لتسجيل عامل ثانٍ أثناء التسجيل. قد تفضّل التطبيقات التي تريد تشجيع ميزة "المصادقة المتعدّدة العوامل" ولكن لا تفرضها هذا النهج.

  • توفير إمكانية إضافة عامل ثانٍ من صفحة إدارة الحساب أو الملف الشخصي للمستخدم، بدلاً من شاشة الاشتراك. يقلّل ذلك من المشاكل أثناء عملية التسجيل، مع إتاحة ميزة "المصادقة المتعدّدة العوامل" للمستخدمين الذين يهتمون بالأمان.

  • المطالبة بإضافة عامل ثانٍ تدريجيًا عندما يريد المستخدم الوصول إلى ميزات تتطلب مستوى أمان أعلى.

إعداد أداة التحقّق من reCAPTCHA

قبل أن تتمكّن من إرسال رموز الرسائل القصيرة، عليك إعداد أداة التحقّق من reCAPTCHA. Firebase تستخدم reCAPTCHA لمنع إساءة الاستخدام من خلال التأكّد من أنّ طلبات إثبات رقم الهاتف تأتي من أحد النطاقات المسموح بها لتطبيقك.

لست بحاجة إلى إعداد عميل reCAPTCHA يدويًا، إذ ينشئ كائن RecaptchaVerifier في حزمة تطوير البرامج (SDK) للعميل تلقائيًا أي مفاتيح وأسرار عميل ضرورية ويهيئها.

استخدام شارة reCAPTCHA غير مرئية

يتيح الكائن RecaptchaVerifier استخدام شارة reCAPTCHA غير مرئية، التي يمكنها غالبًا التحقّق من هوية المستخدم بدون الحاجة إلى أي تفاعل. لاستخدام شارة reCAPTCHA غير مرئية، أنشئ كائن RecaptchaVerifier مع ضبط المعلمة size على invisible، وحدِّد رقم تعريف عنصر في واجهة المستخدم الذي يبدأ عملية تسجيل ميزة "المصادقة المتعدّدة العوامل":

Web

import { RecaptchaVerifier, getAuth } from "firebase/auth";

const recaptchaVerifier = new RecaptchaVerifier(getAuth(), "sign-in-button", {
    "size": "invisible",
    "callback": function(response) {
        // reCAPTCHA solved, you can proceed with
        // phoneAuthProvider.verifyPhoneNumber(...).
        onSolvedRecaptcha();
    }
});

Web

var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
'size': 'invisible',
'callback': function(response) {
  // reCAPTCHA solved, you can proceed with phoneAuthProvider.verifyPhoneNumber(...).
  onSolvedRecaptcha();
}
});

استخدام أداة reCAPTCHA

لاستخدام أداة reCAPTCHA مرئية، أنشئ عنصر HTML يحتوي على الأداة، ثم أنشئ كائن RecaptchaVerifier باستخدام رقم تعريف حاوية واجهة المستخدم. يمكنك أيضًا اختياريًا ضبط عمليات معاودة الاتصال التي يتم استدعاؤها عند حلّ اختبار reCAPTCHA أو انتهاء صلاحيته:

Web

import { RecaptchaVerifier, getAuth } from "firebase/auth";

const recaptchaVerifier = new RecaptchaVerifier(
    getAuth(),
    "recaptcha-container",

    // Optional reCAPTCHA parameters.
    {
      "size": "normal",
      "callback": function(response) {
        // reCAPTCHA solved, you can proceed with
        // phoneAuthProvider.verifyPhoneNumber(...).
        onSolvedRecaptcha();
      },
      "expired-callback": function() {
        // Response expired. Ask user to solve reCAPTCHA again.
        // ...
      }
    }
);

Web

var recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
  'recaptcha-container',
  // Optional reCAPTCHA parameters.
  {
    'size': 'normal',
    'callback': function(response) {
      // reCAPTCHA solved, you can proceed with phoneAuthProvider.verifyPhoneNumber(...).
      // ...
      onSolvedRecaptcha();
    },
    'expired-callback': function() {
      // Response expired. Ask user to solve reCAPTCHA again.
      // ...
    }
  });

العرض المسبق لـ reCAPTCHA

يمكنك اختياريًا العرض المسبق لـ reCAPTCHA قبل بدء عملية تسجيل ميزة "التحقّق بخطوتين":

Web

recaptchaVerifier.render()
    .then(function (widgetId) {
        window.recaptchaWidgetId = widgetId;
    });

Web

recaptchaVerifier.render()
  .then(function(widgetId) {
    window.recaptchaWidgetId = widgetId;
  });

بعد أن يتم حلّ render()، ستحصل على رقم تعريف أداة reCAPTCHA، الذي يمكنك استخدامه لإجراء طلبات إلى reCAPTCHA API:

var recaptchaResponse = grecaptcha.getResponse(window.recaptchaWidgetId);

تجرّد RecaptchaVerifier هذه المنطقية باستخدام طريقة التحقّق، لذا ليس عليك التعامل مع المتغيّر grecaptcha مباشرةً.

تسجيل عامل ثانٍ

لتسجيل عامل ثانوي جديد لمستخدم:

  1. أعِد مصادقة المستخدم.

  2. اطلب من المستخدم إدخال رقم هاتفه.

  3. هيِّئ أداة التحقّق من reCAPTCHA كما هو موضّح في القسم السابق. يمكنك تخطّي هذه الخطوة إذا كان قد تم إعداد مثيل RecaptchaVerifier:

    Web

    import { RecaptchaVerifier, getAuth } from "firebase/auth";
    
    const recaptchaVerifier = new RecaptchaVerifier(
      getAuth(),'recaptcha-container-id', undefined);
    

    Web

    var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container-id');
    
  4. احصل على جلسة متعددة العوامل للمستخدم:

    Web

    import { multiFactor } from "firebase/auth";
    
    multiFactor(user).getSession().then(function (multiFactorSession) {
        // ...
    });
    

    Web

    user.multiFactor.getSession().then(function(multiFactorSession) {
      // ...
    })
    
  5. هيِّئ كائن PhoneInfoOptions باستخدام رقم هاتف المستخدم والجلسة المتعدّدة العوامل:

    Web

    // Specify the phone number and pass the MFA session.
    const phoneInfoOptions = {
      phoneNumber: phoneNumber,
      session: multiFactorSession
    };
    

    Web

    // Specify the phone number and pass the MFA session.
    var phoneInfoOptions = {
      phoneNumber: phoneNumber,
      session: multiFactorSession
    };
    
  6. أرسِل رسالة تحقّق إلى هاتف المستخدم:

    Web

    import { PhoneAuthProvider } from "firebase/auth";
    
    const phoneAuthProvider = new PhoneAuthProvider(auth);
    phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier)
        .then(function (verificationId) {
            // verificationId will be needed to complete enrollment.
        });
    

    Web

    var phoneAuthProvider = new firebase.auth.PhoneAuthProvider();
    // Send SMS verification code.
    return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier)
      .then(function(verificationId) {
        // verificationId will be needed for enrollment completion.
      })
    

    على الرغم من أنّ ذلك ليس مطلوبًا، ننصحك بإعلام المستخدمين مسبقًا بأنّهم سيتلقّون رسالة قصيرة، وأنّه سيتم تطبيق الأسعار العادية.

  7. إذا تعذّر تنفيذ الطلب، أعِد ضبط reCAPTCHA، ثم كرِّر الخطوة السابقة ليتمكّن المستخدم من المحاولة مرة أخرى. يُرجى العِلم أنّ verifyPhoneNumber() ستعيد تلقائيًا ضبط reCAPTCHA عند عرض خطأ، لأنّ رموز reCAPTCHA لا يمكن استخدامها إلا مرة واحدة.

    Web

    recaptchaVerifier.clear();
    

    Web

    recaptchaVerifier.clear();
    
  8. بعد إرسال رمز الرسالة القصيرة، اطلب من المستخدم تأكيد الرمز:

    Web

    // Ask user for the verification code. Then:
    const cred = PhoneAuthProvider.credential(verificationId, verificationCode);
    

    Web

    // Ask user for the verification code. Then:
    var cred = firebase.auth.PhoneAuthProvider.credential(verificationId, verificationCode);
    
  9. هيِّئ كائن MultiFactorAssertion باستخدام PhoneAuthCredential:

    Web

    import { PhoneMultiFactorGenerator } from "firebase/auth";
    
    const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);
    

    Web

    var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
    
  10. أكمِل عملية التسجيل. يمكنك اختياريًا تحديد اسم عرض للعامل الثاني. يكون ذلك مفيدًا للمستخدمين الذين لديهم عوامل ثانية متعددة، لأنّه يتم إخفاء رقم الهاتف أثناء عملية المصادقة (على سبيل المثال، ‎+1******1234).

    Web

    // Complete enrollment. This will update the underlying tokens
    // and trigger ID token change listener.
    multiFactor(user).enroll(multiFactorAssertion, "My personal phone number");
    

    Web

    // Complete enrollment. This will update the underlying tokens
    // and trigger ID token change listener.
    user.multiFactor.enroll(multiFactorAssertion, 'My personal phone number');
    

يعرض الرمز البرمجي أدناه مثالاً كاملاً على تسجيل عامل ثانٍ:

Web

import {
    multiFactor, PhoneAuthProvider, PhoneMultiFactorGenerator,
    RecaptchaVerifier, getAuth
} from "firebase/auth";

const recaptchaVerifier = new RecaptchaVerifier(getAuth(),
    'recaptcha-container-id', undefined);
multiFactor(user).getSession()
    .then(function (multiFactorSession) {
        // Specify the phone number and pass the MFA session.
        const phoneInfoOptions = {
            phoneNumber: phoneNumber,
            session: multiFactorSession
        };

        const phoneAuthProvider = new PhoneAuthProvider(auth);

        // Send SMS verification code.
        return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier);
    }).then(function (verificationId) {
        // Ask user for the verification code. Then:
        const cred = PhoneAuthProvider.credential(verificationId, verificationCode);
        const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);

        // Complete enrollment.
        return multiFactor(user).enroll(multiFactorAssertion, mfaDisplayName);
    });

Web

var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container-id');
user.multiFactor.getSession().then(function(multiFactorSession) {
  // Specify the phone number and pass the MFA session.
  var phoneInfoOptions = {
    phoneNumber: phoneNumber,
    session: multiFactorSession
  };
  var phoneAuthProvider = new firebase.auth.PhoneAuthProvider();
  // Send SMS verification code.
  return phoneAuthProvider.verifyPhoneNumber(
      phoneInfoOptions, recaptchaVerifier);
})
.then(function(verificationId) {
  // Ask user for the verification code.
  var cred = firebase.auth.PhoneAuthProvider.credential(verificationId, verificationCode);
  var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
  // Complete enrollment.
  return user.multiFactor.enroll(multiFactorAssertion, mfaDisplayName);
});

تهانينا! لقد سجّلت بنجاح عامل مصادقة ثانٍ لمستخدم.

تسجيل دخول المستخدمين باستخدام عامل ثانٍ

لتسجيل دخول مستخدم باستخدام ميزة "التحقّق بخطوتين" عبر الرسائل القصيرة:

  1. سجِّل دخول المستخدم باستخدام العامل الأول، ثم رصد الخطأ auth/multi-factor-auth-required. يحتوي هذا الخطأ على أداة حلّ، وتلميحات حول العوامل الثانية المسجّلة، وجلسة أساسية تثبت أنّ المستخدم قد تمت مصادقته بنجاح باستخدام العامل الأول.

    على سبيل المثال، إذا كان العامل الأول للمستخدم هو عنوان بريد إلكتروني وكلمة مرور:

    Web

    import { getAuth, signInWithEmailAndPassword, getMultiFactorResolver} from "firebase/auth";
    
    const auth = getAuth();
    signInWithEmailAndPassword(auth, email, password)
        .then(function (userCredential) {
            // User successfully signed in and is not enrolled with a second factor.
        })
        .catch(function (error) {
            if (error.code == 'auth/multi-factor-auth-required') {
                // The user is a multi-factor user. Second factor challenge is required.
                resolver = getMultiFactorResolver(auth, error);
                // ...
            } else if (error.code == 'auth/wrong-password') {
                // Handle other errors such as wrong password.
            }
    });
    

    Web

    firebase.auth().signInWithEmailAndPassword(email, password)
      .then(function(userCredential) {
        // User successfully signed in and is not enrolled with a second factor.
      })
      .catch(function(error) {
        if (error.code == 'auth/multi-factor-auth-required') {
          // The user is a multi-factor user. Second factor challenge is required.
          resolver = error.resolver;
          // ...
        } else if (error.code == 'auth/wrong-password') {
          // Handle other errors such as wrong password.
        } ...
      });
    

    إذا كان العامل الأول للمستخدم هو مزود خدمة موحّد، مثل OAuth أو SAML أو OIDC، رصد الخطأ بعد استدعاء signInWithPopup() أو signInWithRedirect().

  2. إذا كان لدى المستخدم عوامل ثانية متعددة مسجّلة، اطلب منه تحديد العامل الذي يريد استخدامه:

    Web

    // Ask user which second factor to use.
    // You can get the masked phone number via resolver.hints[selectedIndex].phoneNumber
    // You can get the display name via resolver.hints[selectedIndex].displayName
    
    if (resolver.hints[selectedIndex].factorId ===
        PhoneMultiFactorGenerator.FACTOR_ID) {
        // User selected a phone second factor.
        // ...
    } else if (resolver.hints[selectedIndex].factorId ===
               TotpMultiFactorGenerator.FACTOR_ID) {
        // User selected a TOTP second factor.
        // ...
    } else {
        // Unsupported second factor.
    }
    

    Web

    // Ask user which second factor to use.
    // You can get the masked phone number via resolver.hints[selectedIndex].phoneNumber
    // You can get the display name via resolver.hints[selectedIndex].displayName
    if (resolver.hints[selectedIndex].factorId === firebase.auth.PhoneMultiFactorGenerator.FACTOR_ID) {
      // User selected a phone second factor.
      // ...
    } else if (resolver.hints[selectedIndex].factorId === firebase.auth.TotpMultiFactorGenerator.FACTOR_ID) {
      // User selected a TOTP second factor.
      // ...
    } else {
      // Unsupported second factor.
    }
    
  3. هيِّئ أداة التحقّق من reCAPTCHA كما هو موضّح في القسم السابق. يمكنك تخطّي هذه الخطوة إذا كان قد تم إعداد مثيل RecaptchaVerifier:

    Web

    import { RecaptchaVerifier, getAuth } from "firebase/auth";
    
    recaptchaVerifier = new RecaptchaVerifier(getAuth(),
        'recaptcha-container-id', undefined);
    

    Web

    var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container-id');
    
  4. هيِّئ كائن PhoneInfoOptions باستخدام رقم هاتف المستخدم والجلسة المتعدّدة العوامل. يتم تضمين هذه القيم في كائن resolver الذي تم تمريره إلى الخطأ auth/multi-factor-auth-required:

    Web

    const phoneInfoOptions = {
        multiFactorHint: resolver.hints[selectedIndex],
        session: resolver.session
    };
    

    Web

    var phoneInfoOptions = {
      multiFactorHint: resolver.hints[selectedIndex],
      session: resolver.session
    };
    
  5. أرسِل رسالة تحقّق إلى هاتف المستخدم:

    Web

    // Send SMS verification code.
    const phoneAuthProvider = new PhoneAuthProvider(auth);
    phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier)
        .then(function (verificationId) {
            // verificationId will be needed for sign-in completion.
        });
    

    Web

    var phoneAuthProvider = new firebase.auth.PhoneAuthProvider();
    // Send SMS verification code.
    return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier)
      .then(function(verificationId) {
        // verificationId will be needed for sign-in completion.
      })
    
  6. إذا تعذّر تنفيذ الطلب، أعِد ضبط reCAPTCHA، ثم كرِّر الخطوة السابقة ليتمكّن المستخدم من المحاولة مرة أخرى:

    Web

    recaptchaVerifier.clear();
    

    Web

    recaptchaVerifier.clear();
    
  7. بعد إرسال رمز الرسالة القصيرة، اطلب من المستخدم تأكيد الرمز:

    Web

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

    Web

    // Ask user for the verification code. Then:
    var cred = firebase.auth.PhoneAuthProvider.credential(verificationId, verificationCode);
    
  8. هيِّئ كائن MultiFactorAssertion باستخدام PhoneAuthCredential:

    Web

    const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);
    

    Web

    var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
    
  9. استدعِ resolver.resolveSignIn() لإكمال المصادقة الثانوية. يمكنك بعد ذلك الوصول إلى نتيجة تسجيل الدخول الأصلية، التي تتضمّن البيانات العادية الخاصة بمزوّد الخدمة وبيانات اعتماد المصادقة:

    Web

    // Complete sign-in. This will also trigger the Auth state listeners.
    resolver.resolveSignIn(multiFactorAssertion)
        .then(function (userCredential) {
            // userCredential will also contain the user, additionalUserInfo, optional
            // credential (null for email/password) associated with the first factor sign-in.
    
            // For example, if the user signed in with Google as a first factor,
            // userCredential.additionalUserInfo will contain data related to Google
            // provider that the user signed in with.
            // - user.credential contains the Google OAuth credential.
            // - user.credential.accessToken contains the Google OAuth access token.
            // - user.credential.idToken contains the Google OAuth ID token.
        });
    

    Web

    // Complete sign-in. This will also trigger the Auth state listeners.
    resolver.resolveSignIn(multiFactorAssertion)
      .then(function(userCredential) {
        // userCredential will also contain the user, additionalUserInfo, optional
        // credential (null for email/password) associated with the first factor sign-in.
        // For example, if the user signed in with Google as a first factor,
        // userCredential.additionalUserInfo will contain data related to Google provider that
        // the user signed in with.
        // user.credential contains the Google OAuth credential.
        // user.credential.accessToken contains the Google OAuth access token.
        // user.credential.idToken contains the Google OAuth ID token.
      });
    

يعرض الرمز البرمجي أدناه مثالاً كاملاً على تسجيل دخول مستخدم متعدد العوامل:

Web

import {
    getAuth,
    getMultiFactorResolver,
    PhoneAuthProvider,
    PhoneMultiFactorGenerator,
    RecaptchaVerifier,
    signInWithEmailAndPassword
} from "firebase/auth";

const recaptchaVerifier = new RecaptchaVerifier(getAuth(),
    'recaptcha-container-id', undefined);

const auth = getAuth();
signInWithEmailAndPassword(auth, email, password)
    .then(function (userCredential) {
        // User is not enrolled with a second factor and is successfully
        // signed in.
        // ...
    })
    .catch(function (error) {
        if (error.code == 'auth/multi-factor-auth-required') {
            const resolver = getMultiFactorResolver(auth, error);
            // Ask user which second factor to use.
            if (resolver.hints[selectedIndex].factorId ===
                PhoneMultiFactorGenerator.FACTOR_ID) {
                const phoneInfoOptions = {
                    multiFactorHint: resolver.hints[selectedIndex],
                    session: resolver.session
                };
                const phoneAuthProvider = new PhoneAuthProvider(auth);
                // Send SMS verification code
                return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier)
                    .then(function (verificationId) {
                        // Ask user for the SMS verification code. Then:
                        const cred = PhoneAuthProvider.credential(
                            verificationId, verificationCode);
                        const multiFactorAssertion =
                            PhoneMultiFactorGenerator.assertion(cred);
                        // Complete sign-in.
                        return resolver.resolveSignIn(multiFactorAssertion)
                    })
                    .then(function (userCredential) {
                        // User successfully signed in with the second factor phone number.
                    });
            } else if (resolver.hints[selectedIndex].factorId ===
                       TotpMultiFactorGenerator.FACTOR_ID) {
                // Handle TOTP MFA.
                // ...
            } else {
                // Unsupported second factor.
            }
        } else if (error.code == 'auth/wrong-password') {
            // Handle other errors such as wrong password.
        }
    });

Web

var resolver;
firebase.auth().signInWithEmailAndPassword(email, password)
  .then(function(userCredential) {
    // User is not enrolled with a second factor and is successfully signed in.
    // ...
  })
  .catch(function(error) {
    if (error.code == 'auth/multi-factor-auth-required') {
      resolver = error.resolver;
      // Ask user which second factor to use.
      if (resolver.hints[selectedIndex].factorId ===
          firebase.auth.PhoneMultiFactorGenerator.FACTOR_ID) {
        var phoneInfoOptions = {
          multiFactorHint: resolver.hints[selectedIndex],
          session: resolver.session
        };
        var phoneAuthProvider = new firebase.auth.PhoneAuthProvider();
        // Send SMS verification code
        return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier)
          .then(function(verificationId) {
            // Ask user for the SMS verification code.
            var cred = firebase.auth.PhoneAuthProvider.credential(
                verificationId, verificationCode);
            var multiFactorAssertion =
                firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
            // Complete sign-in.
            return resolver.resolveSignIn(multiFactorAssertion)
          })
          .then(function(userCredential) {
            // User successfully signed in with the second factor phone number.
          });
      } else if (resolver.hints[selectedIndex].factorId ===
        firebase.auth.TotpMultiFactorGenerator.FACTOR_ID) {
        // Handle TOTP MFA.
        // ...
      } else {
        // Unsupported second factor.
      }
    } else if (error.code == 'auth/wrong-password') {
      // Handle other errors such as wrong password.
    } ...
  });

تهانينا! لقد سجّلت دخول مستخدم بنجاح باستخدام ميزة "المصادقة المتعدّدة العوامل".

الخطوات التالية