Ajouter l'authentification multifacteur à votre application Web

Ce document explique comment ajouter l'authentification multifacteur par SMS à votre application Web.

L'authentification multifacteur renforce la sécurité de votre application. Bien que les pirates informatiques compromettent les mots de passe et les comptes de réseaux sociaux, l'interception des SMS est plus difficile.

Avant de commencer

  1. Activer un fournisseur compatible avec l'authentification multifacteur. y compris :

    • Adresse e-mail et mot de passe
    • Envoyer le lien par e-mail
    • Google
    • Facebook
    • Twitter
    • GitHub
    • Microsoft
    • Yahoo
    • LinkedIn
    • SAML
    • OIDC
  2. Assurez-vous que votre application valide les adresses e-mail des utilisateurs. L'authentification multifacteur nécessite une validation de l'adresse e-mail. Cela empêche les utilisateurs malveillants de s'enregistrer à un service avec une adresse e-mail dont ils ne sont pas propriétaire, puis de bloquer le propriétaire réel en ajoutant un second facteur.

Utiliser l'architecture mutualisée

Si vous activez l'authentification multifacteur pour l'utiliser dans un environnement multilocataire, veillez à effectuer les étapes suivantes (en plus des autres instructions fournies dans ce document) :

  • Dans Cloud Console, sélectionnez le locataire avec lequel vous souhaitez travailler.

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

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

Activer l'authentification multifacteur

  1. Accédez à la page MFA Identity Platform dans Cloud Console.
    Accéder à la page de l'authentification multifacteur

  2. Dans la zone intitulée Authentification multifacteur par SMS, cliquez sur Activer.

  3. Saisissez les numéros de téléphone avec lesquels vous souhaitez tester votre application. Bien que cette étape soit facultative, il est fortement recommandé d'enregistrer des numéros de téléphone de test pour éviter toute limitation lors du développement.

  4. Si vous n'avez pas encore autorisé le domaine de votre application, ajoutez-le à la liste des autorisations en cliquant sur Ajouter un domaine à droite.

  5. Cliquez sur Enregistrer.

Choisir un modèle d'inscription

Vous pouvez décider si votre application nécessite une authentification multifacteur, et comment et quand inscrire vos utilisateurs. Voici quelques modèles courants :

  • 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.

  • Proposez une option désactivable pour inscrire un second facteur lors de l'enregistrement. Les applications qui souhaitent encourager mais pas exiger l'authentification multifacteur peuvent préférer cette approche.

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

  • Exigez l'ajout incrémentiel d'un second facteur lorsque l'utilisateur souhaite accéder aux fonctionnalités présentant des exigences de sécurité accrues.

Configurer l'outil de vérification reCAPTCHA

Avant de pouvoir envoyer des codes SMS, vous devez configurer un outil de validation reCAPTCHA. Identity Platform utilise reCAPTCHA pour éviter les abus en garantissant que les demandes de validation 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 codes secrets et les clés de client nécessaires.

Utiliser la méthode reCAPTCHA invisible

L'objet RecaptchaVerifier est compatible avec la méthode reCAPTCHA invisible, qui permet souvent de valider l'utilisateur sans aucune interaction. Pour utiliser un reCAPTCHA invisible, créez une RecaptchaVerifier en définissant le paramètre size sur invisible, puis spécifiez l'ID de l'élément d'interface utilisateur qui lance l'inscription multifacteur:

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 qui contiendra le widget, puis créez un objet RecaptchaVerifier avec l'ID du conteneur d'interface utilisateur. Vous pouvez également définir des rappels appelés lorsque le test reCAPTCHA est résolu ou expire :

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éafficher la méthode reCAPTCHA

Si vous le souhaitez, vous pouvez préafficher la méthode reCAPTCHA avant de lancer l'inscription à deux facteurs :

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

Une fois l'opération render() résolue, vous obtenez l'ID de widget de la méthode reCAPTCHA, que vous pouvez utiliser pour appeler l'API reCAPTCHA :

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

Inscrire un second facteur

Pour inscrire un nouveau facteur secondaire pour un utilisateur, procédez comme suit :

  1. Réauthentifiez l'utilisateur.

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

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

    var recaptchaVerifier = new firebase.auth.RecaptchaVerifier(container);
    
  4. Obtenez une session multifacteur pour l'utilisateur :

    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 :

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

    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 préalablement les utilisateurs qu'ils recevront un SMS, et que les tarifs standards s'appliquent.

  7. Si la requête échoue, réinitialisez la méthode reCAPTCHA, puis répétez l'étape précédente afin que l'utilisateur puisse réessayer. Notez que verifyPhoneNumber() réinitialise automatiquement la méthode reCAPTCHA lorsqu'il génère une erreur, car les jetons reCAPTCHA ne sont utilisés qu'une seule fois.

    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 le vérifier :

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

    var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
    
  10. Terminez l'inscription. Vous pouvez éventuellement spécifier un nom à afficher pour le deuxième facteur. Cela s'avère utile pour les utilisateurs qui ont plusieurs facteurs, car le numéro de téléphone est masqué pendant le processus d'authentification (par exemple, +1******1234).

    // 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 second facteur :

var recaptchaVerifier = new firebase.auth.RecaptchaVerifier(container);
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);
});

Félicitations ! Vous avez enregistré un second facteur d'authentification pour un utilisateur.

Connecter des utilisateurs avec un second facteur

Pour connecter un utilisateur via la validation SMS à deux facteurs, procédez comme suit :

  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 attestant que l'utilisateur s'est authentifié avec succès avec le premier facteur.

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

    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, détectez l'erreur après avoir appelé signInWithPopup() ou signInWithRedirect().

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

    // 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é à la section précédente. Ignorez cette étape si une instance RecaptchaValidator est déjà configurée :

    var recaptchaVerifier = new firebase.auth.RecaptchaVerifier(container);
    
  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 resolver transmis à l'erreur auth/multi-factor-auth-required :

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

    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 la méthode reCAPTCHA, puis répétez l'étape précédente afin que l'utilisateur puisse réessayer :

    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 le vérifier :

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

    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 spécifiques au fournisseur et les identifiants d'authentification :

    // 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 illustre un exemple complet de connexion d'un utilisateur multifacteur :

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

Félicitations ! Vous avez connecté un utilisateur à l'aide de l'authentification multifacteur.

Étape suivante