Ajouter l'authentification multifacteur TOTP à votre application Web

Si vous êtes passé à Firebase Authentication with Identity Platform, vous pouvez ajouter l'authentification multifacteur (MFA) par mot de passe à usage unique basé sur le temps (TOTP) à votre application.

Firebase Authentication with Identity Platform vous permet d'utiliser un TOTP comme facteur supplémentaire pour l'authentification multifacteur. Lorsque vous activez cette fonctionnalité, les utilisateurs qui tentent de se connecter à votre application voient une demande de TOTP. Pour le générer, ils doivent utiliser une application d'authentification capable de générer des codes TOTP valides, comme Google Authenticator.

Avant de commencer

  1. Activez au moins un fournisseur compatible avec l'authentification multifacteur. Notez que tous les fournisseurs sauf les suivants sont compatibles avec l'authentification multifacteur :

    • Authentification par téléphone
    • Authentification anonyme
    • Jetons d'authentification personnalisés
    • Game Center d'Apple
  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 de l'adresse e-mail en ajoutant un second facteur.

  3. Si vous ne l'avez pas déjà fait, installez le SDK Firebase JavaScript.

    L'authentification multifacteur par TOTP n'est compatible qu'avec le SDK Web modulaire, versions 9.19.1 et ultérieures.

Activer l'authentification multifacteur par TOTP

Pour activer le TOTP comme second facteur, utilisez le Admin SDK ou appelez le point de terminaison REST de configuration du projet.

Pour utiliser le Admin SDK, procédez comme suit :

  1. Si vous ne l'avez pas déjà fait, installez le SDK Firebase Admin Node.js.

    L'authentification multifacteur par TOTP n'est compatible qu'avec les versions 11.6.0 et ultérieures du SDK Firebase Admin Node.js.

  2. Exécutez la commande suivante :

    import { getAuth } from 'firebase-admin/auth';
    
    getAuth().projectConfigManager().updateProjectConfig(
    {
          multiFactorConfig: {
              providerConfigs: [{
                  state: "ENABLED",
                  totpProviderConfig: {
                      adjacentIntervals: NUM_ADJ_INTERVALS
                  }
              }]
          }
    })
    

    Remplacez les éléments suivants :

    • NUM_ADJ_INTERVALS: nombre d'intervalles de fenêtre temporelle adjacents à partir desquels accepter les TOTP, de zéro à dix. La valeur par défaut est cinq.

      Les TOTP fonctionnent en s'assurant que lorsque deux parties (le prouveur et le validateur) génèrent des OTP dans la même fenêtre temporelle (généralement 30 secondes), elles génèrent le même mot de passe. Toutefois, pour tenir compte de la dérive de l'horloge entre les parties et du temps de réponse humaine, vous pouvez configurer le service TOTP pour qu'il accepte également les TOTP provenant de fenêtres adjacentes.

Pour activer l'authentification multifacteur par TOTP à l'aide de l'API REST, exécutez la commande suivante :

curl -X PATCH "https://identitytoolkit.googleapis.com/admin/v2/projects/PROJECT_ID/config?updateMask=mfa" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: PROJECT_ID" \
    -d \
    '{
        "mfa": {
          "providerConfigs": [{
            "state": "ENABLED",
            "totpProviderConfig": {
              "adjacentIntervals": NUM_ADJ_INTERVALS
            }
          }]
       }
    }'

Remplacez les éléments suivants :

  • PROJECT_ID : ID du projet.
  • NUM_ADJ_INTERVALS: nombre d'intervalles de fenêtre temporelle, de zéro à dix. La valeur par défaut est cinq.

    Les TOTP fonctionnent en s'assurant que lorsque deux parties (le prouveur et le validateur) génèrent des OTP dans la même fenêtre temporelle (généralement 30 secondes), elles génèrent le même mot de passe. Toutefois, pour tenir compte de la dérive de l'horloge entre les parties et du temps de réponse humaine, vous pouvez configurer le service TOTP pour qu'il accepte également les TOTP provenant de fenêtres adjacentes.

Choisir un modèle d'inscription

Vous pouvez choisir 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. Si vous souhaitez encourager l'authentification multifacteur dans votre application sans l'exiger, vous pouvez utiliser 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.

Inscrire des utilisateurs à l'authentification multifacteur par TOTP

Une fois que vous avez activé l'authentification multifacteur par TOTP comme second facteur pour votre application, implémentez une logique côté client pour inscrire les utilisateurs à l'authentification multifacteur par TOTP :

  1. Importez les classes et fonctions d'authentification multifacteur requises :

    import {
      multiFactor,
      TotpMultiFactorGenerator,
      TotpSecret,
      getAuth,
    } from "firebase/auth";
    
  2. Réauthentifiez l'utilisateur.

  3. Générez un secret TOTP pour l'utilisateur authentifié :

    // Generate a TOTP secret.
    const multiFactorSession = await multiFactor(currentUser).getSession();
    const totpSecret = await TotpMultiFactorGenerator.generateSecret(
      multiFactorSession
    );
    
  4. Affichez le secret à l'utilisateur et invitez-le à le saisir dans son application d'authentification.

    Avec de nombreuses applications d'authentification, les utilisateurs peuvent rapidement ajouter de nouveaux secrets TOTP en scannant un code QR qui représente un URI de clé compatible avec Google Authenticator. Pour générer un code QR à cet effet, générez l'URI avec generateQrCodeUrl() , puis encodez-le à l'aide de la bibliothèque de codes QR de votre choix. Exemple :

    const totpUri = totpSecret.generateQrCodeUrl(
        currentUser.email,
        "Your App's Name"
    );
    await QRExampleLib.toCanvas(totpUri, qrElement);
    

    Que vous affichiez ou non un code QR, affichez toujours la clé secrète pour prendre en charge les applications d'authentification qui ne peuvent pas lire les codes QR :

    // Also display this key:
    const secret = totpSecret.secretKey;
    

    Une fois que l'utilisateur a ajouté son secret à son application d'authentification, celle-ci commence à générer des TOTP.

  5. Invitez l'utilisateur à saisir le TOTP affiché dans son application d'authentification et à l'utiliser pour finaliser l'inscription à l'authentification multifacteur :

    // Ask the user for a verification code from the authenticator app.
    const verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    const multiFactorAssertion = TotpMultiFactorGenerator.assertionForEnrollment(
      totpSecret,
      verificationCode
    );
    await multiFactor(currentUser).enroll(multiFactorAssertion, mfaDisplayName);
    

Connecter des utilisateurs avec un second facteur

Pour connecter des utilisateurs avec l'authentification multifacteur par TOTP, utilisez le code suivant :

  1. Importez les classes et fonctions d'authentification multifacteur requises :

    import {
        getAuth,
        getMultiFactorResolver,
        TotpMultiFactorGenerator,
    } from "firebase/auth";
    
  2. Appelez l'une des méthodes signInWith-, comme si vous n'utilisiez pas l'authentification multifacteur. (Par exemple, signInWithEmailAndPassword().) Si la méthode génère une erreur auth/multi-factor-auth-required, démarrez le flux d'authentification multifacteur de votre application.

    try {
        const userCredential = await signInWithEmailAndPassword(
            getAuth(),
            email,
            password
        );
        // If the user is not enrolled with a second factor and provided valid
        // credentials, sign-in succeeds.
    
        // (If your app requires MFA, this could be considered an error
        // condition, which you would resolve by forcing the user to enroll a
        // second factor.)
    
        // ...
    } catch (error) {
        switch (error.code) {
            case "auth/multi-factor-auth-required":
                // Initiate your second factor sign-in flow. (See next step.)
                // ...
                break;
            case ...:  // Handle other errors, such as wrong passwords.
                break;
        }
    }
    
  3. Le flux d'authentification multifacteur de votre application doit d'abord inviter l'utilisateur à choisir le second facteur qu'il souhaite utiliser. Vous pouvez obtenir une liste des seconds facteurs compatibles en examinant la propriété hints d'une instance MultiFactorResolver :

    const mfaResolver = getMultiFactorResolver(getAuth(), error);
    const enrolledFactors = mfaResolver.hints.map(info => info.displayName);
    
  4. Si l'utilisateur choisit d'utiliser un TOTP, invitez-le à saisir le TOTP affiché dans son application d'authentification et à l'utiliser pour se connecter :

    switch (mfaResolver.hints[selectedIndex].factorId) {
        case TotpMultiFactorGenerator.FACTOR_ID:
            const otpFromAuthenticator = // OTP typed by the user.
            const multiFactorAssertion =
                TotpMultiFactorGenerator.assertionForSignIn(
                    mfaResolver.hints[selectedIndex].uid,
                    otpFromAuthenticator
                );
            try {
                const userCredential = await mfaResolver.resolveSignIn(
                    multiFactorAssertion
                );
                // Successfully signed in!
            } catch (error) {
                // Invalid or expired OTP.
            }
            break;
        case PhoneMultiFactorGenerator.FACTOR_ID:
            // Handle SMS second factor.
            break;
        default:
            // Unsupported second factor?
            break;
    }
    

Se désinscrire de l'authentification multifacteur par TOTP

Cette section explique comment gérer la désinscription d'un utilisateur de l'authentification multifacteur par TOTP.

Si un utilisateur s'est inscrit à plusieurs options d'authentification multifacteur et qu'il se désinscrit de l'option la plus récemment activée, il reçoit un message auth/user-token-expired et est déconnecté. L'utilisateur doit se reconnecter et valider ses identifiants existants, par exemple une adresse e-mail et un mot de passe.

Pour désinscrire l'utilisateur, gérer l'erreur et déclencher une réauthentification, utilisez le code suivant :

import {
    EmailAuthProvider,
    TotpMultiFactorGenerator,
    getAuth,
    multiFactor,
    reauthenticateWithCredential,
} from "firebase/auth";

try {
    // Unenroll from TOTP MFA.
    await multiFactor(currentUser).unenroll(mfaEnrollmentId);
} catch  (error) {
    if (error.code === 'auth/user-token-expired') {
        // If the user was signed out, re-authenticate them.

        // For example, if they signed in with a password, prompt them to
        // provide it again, then call `reauthenticateWithCredential()` as shown
        // below.

        const credential = EmailAuthProvider.credential(email, password);
        await reauthenticateWithCredential(
            currentUser,
            credential
        );
    }
}

Étape suivante