Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

Ajoutez une authentification multifacteur à votre application Web

Restez organisé à l'aide des collections Enregistrez et classez les contenus selon vos préférences.

Si vous avez effectué la mise à niveau vers Firebase Authentication with Identity Platform, vous pouvez ajouter l'authentification multifacteur SMS à votre application Web.

L'authentification multifacteur augmente la sécurité de votre application. Alors que les attaquants compromettent souvent les mots de passe et les comptes sociaux, l'interception d'un message texte est plus difficile.

Avant que tu commences

  1. Activez au moins un fournisseur prenant en charge l'authentification multifacteur. Chaque fournisseur prend en charge MFA, à l' exception de l'authentification par téléphone, de l'authentification anonyme et d'Apple Game Center.

  2. Assurez-vous que votre application vérifie les e-mails des utilisateurs. MFA nécessite une vérification par e-mail. Cela empêche les acteurs malveillants de s'inscrire à un service avec un e-mail qu'ils ne possèdent pas, puis de verrouiller le véritable propriétaire en ajoutant un deuxième facteur.

Utiliser la multilocation

Si vous activez l'authentification multifacteur pour une utilisation dans un environnement mutualisé , assurez-vous de suivre les étapes suivantes (en plus du reste des instructions de ce document) :

  1. Dans la console GCP, sélectionnez le locataire avec lequel vous souhaitez travailler.

  2. Dans votre code, définissez le champ tenantId de l'instance Auth sur l'ID de votre locataire. Par exemple:

    Web version 9

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

    Web version 8

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

Activer l'authentification multifacteur

  1. Ouvrez la page Authentification > Méthode de connexion de la console Firebase.

  2. Dans la section Avancé , activez Authentification multifacteur SMS .

    Vous devez également entrer les numéros de téléphone avec lesquels vous testerez votre application. Bien que facultatif, l'enregistrement des numéros de téléphone de test est fortement recommandé pour éviter les limitations pendant le développement.

  3. Si vous n'avez pas encore autorisé le domaine de votre application, ajoutez-le à la liste verte sur la page Authentification > Paramètres de la console Firebase.

Choisir un modèle d'inscription

Vous pouvez choisir si votre application requiert une authentification multifacteur, et comment et quand inscrire vos utilisateurs. Certains modèles courants incluent :

  • Inscrivez le deuxième facteur de l'utilisateur dans le cadre de l'inscription. Utilisez cette méthode si votre application nécessite une authentification multifacteur pour tous les utilisateurs.

  • Offrez une option désactivable pour inscrire un deuxième facteur lors de l'inscription. Les applications qui souhaitent encourager, mais pas exiger, l'authentification multifacteur peuvent préférer cette approche.

  • Offrez la possibilité d'ajouter un deuxième facteur à partir de la page de gestion du compte ou du profil de l'utilisateur, au lieu de l'écran d'inscription. Cela minimise les frictions pendant le processus d'inscription, tout en rendant l'authentification multifacteur disponible pour les utilisateurs sensibles à la sécurité.

  • Nécessite l'ajout progressif d'un deuxième facteur lorsque l'utilisateur souhaite accéder à des fonctionnalités avec des exigences de sécurité accrues.

Configurer le vérificateur reCAPTCHA

Avant de pouvoir envoyer des codes SMS, vous devez configurer un vérificateur reCAPTCHA. Firebase utilise reCAPTCHA pour empêcher les abus en s'assurant que les demandes de vérification de numéro de téléphone proviennent de l'un des domaines autorisés de votre application.

Vous n'avez pas besoin de configurer manuellement un client reCAPTCHA ; l'objet RecaptchaVerifier du SDK client crée et initialise automatiquement les clés et secrets client nécessaires.

Utiliser un reCAPTCHA invisible

L'objet RecaptchaVerifier prend en charge le reCAPTCHA invisible , qui peut souvent vérifier l'utilisateur sans nécessiter aucune interaction. Pour utiliser un reCAPTCHA invisible, créez un RecaptchaVerifier avec le paramètre size défini sur invisible et spécifiez l'ID de l'élément d'interface utilisateur qui démarre l'inscription multifacteur :

Web version 9

import { RecaptchaVerifier } from "firebase/auth";

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

Web version 8

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

Utiliser le widget reCAPTCHA

Pour utiliser un widget reCAPTCHA visible, créez un élément HTML pour contenir le widget, puis créez un objet RecaptchaVerifier avec l'ID du conteneur UI. Vous pouvez également éventuellement définir des rappels qui sont invoqués lorsque le reCAPTCHA est résolu ou expire :

Web version 9

import { RecaptchaVerifier } from "firebase/auth";

const recaptchaVerifier = new 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.
        // ...
      }
    }, auth
);

Web version 8

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.
      // ...
    }
  });

Pré-rendu du reCAPTCHA

Si vous le souhaitez, vous pouvez pré-afficher le reCAPTCHA avant de commencer l'inscription à deux facteurs :

Web version 9

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

Web version 8

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

Une fois render() résolu, vous obtenez l'ID du widget reCAPTCHA, que vous pouvez utiliser pour effectuer des appels à l' API reCAPTCHA :

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

Inscrire un deuxième facteur

Pour inscrire un nouveau facteur secondaire pour un utilisateur :

  1. Réauthentifiez l'utilisateur.

  2. Demandez à l'utilisateur d'entrer son numéro de téléphone.

  3. Initialisez le vérificateur reCAPTCHA comme illustré dans la section précédente. Ignorez cette étape si une instance RecaptchaVerifier est déjà configurée :

    Web version 9

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

    Web version 8

    var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container-id');
    
  4. Obtenez une session multi-facteurs pour l'utilisateur :

    Web version 9

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

    Web version 8

    user.multiFactor.getSession().then(function(multiFactorSession) {
      // ...
    })
    
  5. Initialisez un objet PhoneInfoOptions avec le numéro de téléphone de l'utilisateur et la session multifacteur :

    Web version 9

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

    Web version 8

    // Specify the phone number and pass the MFA session.
    var phoneInfoOptions = {
      phoneNumber: phoneNumber,
      session: multiFactorSession
    };
    
  6. Envoyez un message de vérification au téléphone de l'utilisateur :

    Web version 9

    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 version 8

    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.
      })
    

    Bien que cela ne soit pas obligatoire, il est recommandé d'informer les utilisateurs à l'avance qu'ils recevront un SMS et que les tarifs standard s'appliquent.

  7. Si la demande échoue, réinitialisez le reCAPTCHA, puis répétez l'étape précédente pour que l'utilisateur puisse réessayer. Notez que verifyPhoneNumber() réinitialisera automatiquement le reCAPTCHA lorsqu'il génère une erreur, car les jetons reCAPTCHA sont à usage unique.

    Web version 9

    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    recaptchaVerifier.render()
      .then(function(widgetId) {
        grecaptcha.reset(widgetId);
      });
    

    Web version 8

    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    recaptchaVerifier.render()
      .then(function(widgetId) {
        grecaptcha.reset(widgetId);
      });
    
  8. Une fois le code SMS envoyé, demandez à l'utilisateur de vérifier le code :

    Web version 9

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

    Web version 8

    // Ask user for the verification code. Then:
    var cred = firebase.auth.PhoneAuthProvider.credential(verificationId, verificationCode);
    
  9. Initialisez un objet MultiFactorAssertion avec PhoneAuthCredential :

    Web version 9

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

    Web version 8

    var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
    
  10. Complétez l'inscription. Si vous le souhaitez, vous pouvez spécifier un nom d'affichage pour le second facteur. Ceci est utile pour les utilisateurs avec plusieurs seconds facteurs, car le numéro de téléphone est masqué pendant le flux d'authentification (par exemple, +1******1234).

    Web version 9

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

    Web version 8

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

Le code ci-dessous montre un exemple complet d'inscription d'un deuxième facteur :

Web version 9

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

const recaptchaVerifier = new RecaptchaVerifier('recaptcha-container-id', undefined, auth);
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 version 8

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);
});

Toutes nos félicitations! Vous avez enregistré avec succès un deuxième facteur d'authentification pour un utilisateur.

Connexion des utilisateurs avec un deuxième facteur

Pour connecter un utilisateur avec la vérification par SMS à deux facteurs :

  1. Connectez l'utilisateur avec son premier facteur, puis détectez l'erreur auth/multi-factor-auth-required . Cette erreur contient un résolveur, des indices sur les seconds facteurs inscrits et une session sous-jacente prouvant que l'utilisateur s'est authentifié avec succès avec le premier facteur.

    Par exemple, si le premier facteur de l'utilisateur était une adresse e-mail et un mot de passe :

    Web version 9

    import { getAuth, 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 version 8

    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.
        } ...
      });
    

    Si le premier facteur de l'utilisateur est un fournisseur fédéré, tel que OAuth, SAML ou OIDC, interceptez l'erreur après avoir appelé signInWithPopup() ou signInWithRedirect() .

  2. Si l'utilisateur a plusieurs facteurs secondaires inscrits, demandez-lui lequel utiliser :

    Web version 9

    // 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 {
        // Unsupported second factor.
        // Note that only phone second factors are currently supported.
    }
    

    Web version 8

    // 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 {
      // Unsupported second factor.
      // Note that only phone second factors are currently supported.
    }
    
  3. Initialisez le vérificateur reCAPTCHA comme illustré dans la section précédente. Ignorez cette étape si une instance RecaptchaVerifier est déjà configurée :

    Web version 9

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

    Web version 8

    var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container-id');
    
  4. Initialisez un objet PhoneInfoOptions avec le numéro de téléphone de l'utilisateur et la session multifacteur. Ces valeurs sont contenues dans l'objet de resolver transmis à l'erreur auth/multi-factor-auth-required :

    Web version 9

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

    Web version 8

    var phoneInfoOptions = {
      multiFactorHint: resolver.hints[selectedIndex],
      session: resolver.session
    };
    
  5. Envoyez un message de vérification au téléphone de l'utilisateur :

    Web version 9

    // 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 version 8

    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. Si la requête échoue, réinitialisez le reCAPTCHA, puis répétez l'étape précédente pour que l'utilisateur puisse réessayer :

    Web version 9

    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    recaptchaVerifier.render()
      .then(function(widgetId) {
        grecaptcha.reset(widgetId);
      });
    

    Web version 8

    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    recaptchaVerifier.render()
      .then(function(widgetId) {
        grecaptcha.reset(widgetId);
      });
    
  7. Une fois le code SMS envoyé, demandez à l'utilisateur de vérifier le code :

    Web version 9

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

    Web version 8

    // Ask user for the verification code. Then:
    var cred = firebase.auth.PhoneAuthProvider.credential(verificationId, verificationCode);
    
  8. Initialisez un objet MultiFactorAssertion avec PhoneAuthCredential :

    Web version 9

    const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);
    

    Web version 8

    var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
    
  9. Appelez resolver.resolveSignIn() pour terminer l'authentification secondaire. Vous pouvez ensuite accéder au résultat de connexion d'origine, qui inclut les données standard spécifiques au fournisseur et les identifiants d'authentification :

    Web version 9

    // 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 version 8

    // 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.
      });
    

Le code ci-dessous montre un exemple complet de connexion d'un utilisateur multifacteur :

Web version 9

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

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

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 {
                // Unsupported second factor.
            }
        } else if (error.code == 'auth/wrong-password') {
            // Handle other errors such as wrong password.
        }
    });

Web version 8

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 {
        // Unsupported second factor.
      }
    } else if (error.code == 'auth/wrong-password') {
      // Handle other errors such as wrong password.
    } ...
  });

Toutes nos félicitations! Vous avez réussi à connecter un utilisateur à l'aide de l'authentification multifacteur.

Et après