Authentifiez-vous avec Firebase à l'aide d'Email Link en JavaScript

Vous pouvez utiliser Firebase Authentication pour connecter un utilisateur en lui envoyant un e-mail contenant un lien sur lequel il peut cliquer pour se connecter. L'adresse e-mail de l'utilisateur est également validée au cours du processus.

La connexion par e-mail présente de nombreux avantages :

  • Inscription et connexion faciles.
  • Réduction du risque de réutilisation de mots de passe dans les applications, ce qui peut compromettre la sécurité même des mots de passe bien choisis.
  • Capacité à authentifier un utilisateur tout en vérifiant qu'il est le propriétaire légitime d'une adresse e-mail.
  • Pour se connecter, un utilisateur a uniquement besoin d'un compte de messagerie accessible. Il n'est pas nécessaire d'être propriétaire d'un numéro de téléphone ou d'un compte de réseau social.
  • Un utilisateur peut se connecter de manière sécurisée sans avoir à fournir (ni à mémoriser) un mot de passe, ce qui peut être fastidieux sur un appareil mobile.
  • Un utilisateur existant qui s'est déjà connecté avec un identifiant d'adresse e-mail (mot de passe ou fédéré) peut être mis à niveau pour se connecter uniquement avec l'adresse e-mail. Par exemple, un utilisateur qui a oublié son mot de passe peut toujours se connecter sans avoir à le réinitialiser.

Avant de commencer

Si ce n'est pas déjà fait, copiez l'extrait d'initialisation depuis la console Firebase dans votre projet, comme décrit dans Ajouter Firebase à votre projet JavaScript.

Pour connecter les utilisateurs par lien e-mail, vous devez d'abord activer le fournisseur d'adresse e-mail et la méthode de connexion par lien e-mail pour votre projet Firebase :

  1. Dans la console Firebase, accédez à Sécurité > Authentification.

  2. Dans l'onglet Méthode de connexion, activez la méthode de connexion Adresse e-mail/Mot de passe. Notez que la connexion par adresse e-mail/mot de passe doit être activée pour utiliser la connexion par lien envoyé par e-mail.

  3. Dans la même section, activez le fournisseur de connexion Lien envoyé par e-mail (connexion sans mot de passe).

  4. Cliquez sur Enregistrer.

Pour lancer le flux d'authentification, présentez à l'utilisateur une interface qui l'invite à fournir son adresse e-mail, puis appelez sendSignInLinkToEmail pour demander à Firebase d'envoyer le lien d'authentification à l'adresse e-mail de l'utilisateur.

  1. Construisez l'objet ActionCodeSettings, qui fournit à Firebase des instructions sur la façon de créer le lien d'adresse e-mail. Attribuez aux champs suivants les valeurs correspondantes :

    • url : lien profond à intégrer et tout état supplémentaire à transmettre. Si vous ne l'avez pas déjà fait, ajoutez votre domaine à la liste des domaines autorisés :

      1. Dans la consoleFirebase, accédez à l'onglet Paramètres de Sécurité > Authentification > Paramètres.

      2. Dans la section Domaines autorisés, cliquez sur Ajouter un domaine, puis ajoutez votre domaine.

    • android et ios : aident Firebase Authentication à déterminer s'il doit créer un lien Web uniquement ou un lien mobile qui s'ouvre sur un appareil Android ou Apple.
    • handleCodeInApp : définie sur "true". L'opération de connexion doit toujours être effectuée dans l'application, contrairement aux autres actions par e-mail hors bande (réinitialisation du mot de passe et validation de l'adresse e-mail). En effet, à la fin du flux, l'utilisateur doit être connecté et son état d'authentification doit être conservé dans l'application.
    • linkDomain : lorsque des domaines de liens Hosting personnalisés sont définis pour un projet, spécifiez celui à utiliser lorsque le lien doit être ouvert par une application mobile spécifique. Sinon, le domaine par défaut est automatiquement sélectionné (par exemple, PROJECT_ID.firebaseapp.com).
    • dynamicLinkDomain : obsolète. Ne spécifiez pas ce paramètre.

      Web

      const actionCodeSettings = {
        // URL you want to redirect back to. The domain (www.example.com) for this
        // URL must be in the authorized domains list in the Firebase Console.
        url: 'https://www.example.com/finishSignUp?cartId=1234',
        // This must be true.
        handleCodeInApp: true,
        iOS: {
          bundleId: 'com.example.ios'
        },
        android: {
          packageName: 'com.example.android',
          installApp: true,
          minimumVersion: '12'
        },
        // The domain must be configured in Firebase Hosting and owned by the project.
        linkDomain: 'custom-domain.com'
      };

      Web

      var actionCodeSettings = {
        // URL you want to redirect back to. The domain (www.example.com) for this
        // URL must be in the authorized domains list in the Firebase Console.
        url: 'https://www.example.com/finishSignUp?cartId=1234',
        // This must be true.
        handleCodeInApp: true,
        iOS: {
          bundleId: 'com.example.ios'
        },
        android: {
          packageName: 'com.example.android',
          installApp: true,
          minimumVersion: '12'
        },
        dynamicLinkDomain: 'example.page.link'
      };

    Pour en savoir plus sur ActionCodeSettings, consultez la section Transmettre l'état dans les actions par e-mail.

  2. Demandez à l'utilisateur son adresse e-mail.

  3. Envoyez le lien d'authentification à l'adresse e-mail de l'utilisateur et enregistrez-la au cas où il se connecterait par e-mail sur le même appareil.

    Web

    import { getAuth, sendSignInLinkToEmail } from "firebase/auth";
    
    const auth = getAuth();
    sendSignInLinkToEmail(auth, email, actionCodeSettings)
      .then(() => {
        // The link was successfully sent. Inform the user.
        // Save the email locally so you don't need to ask the user for it again
        // if they open the link on the same device.
        window.localStorage.setItem('emailForSignIn', email);
        // ...
      })
      .catch((error) => {
        const errorCode = error.code;
        const errorMessage = error.message;
        // ...
      });

    Web

    firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings)
      .then(() => {
        // The link was successfully sent. Inform the user.
        // Save the email locally so you don't need to ask the user for it again
        // if they open the link on the same device.
        window.localStorage.setItem('emailForSignIn', email);
        // ...
      })
      .catch((error) => {
        var errorCode = error.code;
        var errorMessage = error.message;
        // ...
      });

Problèmes de sécurité

Pour éviter qu'un lien de connexion ne soit utilisé pour se connecter en tant qu'utilisateur non prévu ou sur un appareil non prévu, Firebase Auth exige que l'adresse e-mail de l'utilisateur soit fournie lors de la finalisation du processus de connexion. Pour que la connexion aboutisse, cette adresse e-mail doit correspondre à celle à laquelle le lien de connexion a été envoyé à l'origine.

Vous pouvez simplifier ce flux pour les utilisateurs qui ouvrent le lien de connexion sur le même appareil que celui sur lequel ils demandent le lien, en stockant leur adresse e-mail localement (par exemple, à l'aide de localStorage ou de cookies) lorsque vous envoyez l'e-mail de connexion. Utilisez ensuite cette adresse pour finaliser le processus. Ne transmettez pas l'adresse e-mail de l'utilisateur dans les paramètres de l'URL de redirection et ne la réutilisez pas, car cela peut permettre des injections de session.

Une fois la connexion terminée, tout mécanisme de connexion non validé précédemment sera supprimé pour l'utilisateur et toutes les sessions existantes seront invalidées. Par exemple, si quelqu'un a déjà créé un compte non validé avec la même adresse e-mail et le même mot de passe, le mot de passe de l'utilisateur sera supprimé pour empêcher l'usurpateur qui a revendiqué la propriété et créé ce compte non validé de se reconnecter avec l'adresse e-mail et le mot de passe non validés.

Assurez-vous également d'utiliser une URL HTTPS en production pour éviter que votre lien ne soit potentiellement intercepté par des serveurs intermédiaires.

Finaliser la connexion sur une page Web

Le format du lien profond de l'e-mail est le même que celui utilisé pour les actions par e-mail hors bande (validation de l'adresse e-mail, réinitialisation du mot de passe et révocation du changement d'adresse e-mail). Firebase Auth simplifie cette vérification en fournissant l'API isSignInWithEmailLink pour vérifier si un lien est un lien de connexion avec une adresse e-mail.

Pour finaliser la connexion sur la page de destination, appelez signInWithEmailLink avec l'adresse e-mail de l'utilisateur et le lien vers l'e-mail contenant le code à usage unique.

Web

import { getAuth, isSignInWithEmailLink, signInWithEmailLink } from "firebase/auth";

// Confirm the link is a sign-in with email link.
const auth = getAuth();
if (isSignInWithEmailLink(auth, window.location.href)) {
  // Additional state parameters can also be passed via URL.
  // This can be used to continue the user's intended action before triggering
  // the sign-in operation.
  // Get the email if available. This should be available if the user completes
  // the flow on the same device where they started it.
  let email = window.localStorage.getItem('emailForSignIn');
  if (!email) {
    // User opened the link on a different device. To prevent session fixation
    // attacks, ask the user to provide the associated email again. For example:
    email = window.prompt('Please provide your email for confirmation');
  }
  // The client SDK will parse the code from the link for you.
  signInWithEmailLink(auth, email, window.location.href)
    .then((result) => {
      // Clear email from storage.
      window.localStorage.removeItem('emailForSignIn');
      // You can access the new user by importing getAdditionalUserInfo
      // and calling it with result:
      // getAdditionalUserInfo(result)
      // You can access the user's profile via:
      // getAdditionalUserInfo(result)?.profile
      // You can check if the user is new or existing:
      // getAdditionalUserInfo(result)?.isNewUser
    })
    .catch((error) => {
      // Some error occurred, you can inspect the code: error.code
      // Common errors could be invalid email and invalid or expired OTPs.
    });
}

Web

// Confirm the link is a sign-in with email link.
if (firebase.auth().isSignInWithEmailLink(window.location.href)) {
  // Additional state parameters can also be passed via URL.
  // This can be used to continue the user's intended action before triggering
  // the sign-in operation.
  // Get the email if available. This should be available if the user completes
  // the flow on the same device where they started it.
  var email = window.localStorage.getItem('emailForSignIn');
  if (!email) {
    // User opened the link on a different device. To prevent session fixation
    // attacks, ask the user to provide the associated email again. For example:
    email = window.prompt('Please provide your email for confirmation');
  }
  // The client SDK will parse the code from the link for you.
  firebase.auth().signInWithEmailLink(email, window.location.href)
    .then((result) => {
      // Clear email from storage.
      window.localStorage.removeItem('emailForSignIn');
      // You can access the new user via result.user
      // Additional user info profile not available via:
      // result.additionalUserInfo.profile == null
      // You can check if the user is new or existing:
      // result.additionalUserInfo.isNewUser
    })
    .catch((error) => {
      // Some error occurred, you can inspect the code: error.code
      // Common errors could be invalid email and invalid or expired OTPs.
    });
}

Finaliser la connexion dans une application mobile

Firebase Authentication utilise Firebase Hosting pour envoyer le lien par e-mail à un appareil mobile. Pour que la connexion soit finalisée via l'application mobile, celle-ci doit être configurée pour détecter le lien d'application entrant, analyser le lien profond sous-jacent, puis finaliser la connexion comme elle le fait via le flux Web.

Pour savoir comment gérer la connexion avec un lien envoyé par e-mail dans une application Android, consultez le guide Android.

Pour savoir comment gérer la connexion avec un lien envoyé par e-mail dans une application Apple, consultez le guide des plates-formes Apple.

Vous pouvez également associer cette méthode d'authentification à un utilisateur existant. Par exemple, un utilisateur qui s'est déjà authentifié avec un autre fournisseur, comme un numéro de téléphone, peut ajouter cette méthode de connexion à son compte existant.

La différence se situe dans la deuxième moitié de l'opération :

Web

import { getAuth, linkWithCredential, EmailAuthProvider } from "firebase/auth";

// Construct the email link credential from the current URL.
const credential = EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Link the credential to the current user.
const auth = getAuth();
linkWithCredential(auth.currentUser, credential)
  .then((usercred) => {
    // The provider is now successfully linked.
    // The phone user can now sign in with their phone number or email.
  })
  .catch((error) => {
    // Some error occurred.
  });

Web

// Construct the email link credential from the current URL.
var credential = firebase.auth.EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Link the credential to the current user.
firebase.auth().currentUser.linkWithCredential(credential)
  .then((usercred) => {
    // The provider is now successfully linked.
    // The phone user can now sign in with their phone number or email.
  })
  .catch((error) => {
    // Some error occurred.
  });

Cela peut également être utilisé pour réauthentifier un utilisateur de lien e-mail avant d'exécuter une opération sensible.

Web

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

// Construct the email link credential from the current URL.
const credential = EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Re-authenticate the user with this credential.
const auth = getAuth();
reauthenticateWithCredential(auth.currentUser, credential)
  .then((usercred) => {
    // The user is now successfully re-authenticated and can execute sensitive
    // operations.
  })
  .catch((error) => {
    // Some error occurred.
  });

Web

// Construct the email link credential from the current URL.
var credential = firebase.auth.EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Re-authenticate the user with this credential.
firebase.auth().currentUser.reauthenticateWithCredential(credential)
  .then((usercred) => {
    // The user is now successfully re-authenticated and can execute sensitive
    // operations.
  })
  .catch((error) => {
    // Some error occurred.
  });

Toutefois, comme le flux peut se terminer sur un autre appareil sur lequel l'utilisateur d'origine n'était pas connecté, il est possible que ce flux ne soit pas terminé. Dans ce cas, une erreur peut être affichée à l'utilisateur pour l'obliger à ouvrir le lien sur le même appareil. Certains états peuvent être transmis dans le lien pour fournir des informations sur le type d'opération et l'UID de l'utilisateur.

Si vous avez créé votre projet le 15 septembre 2023 ou après, la protection contre l'énumération des adresses e-mail est activée par défaut. Cette fonctionnalité améliore la sécurité des comptes utilisateur de votre projet, mais elle désactive la méthode fetchSignInMethodsForEmail(), que nous recommandions auparavant pour implémenter des flux axés sur l'identifiant.

Bien que vous puissiez désactiver la protection contre l'énumération d'adresses e-mail pour votre projet, nous vous le déconseillons.

Pour en savoir plus, consultez la documentation sur la protection contre l'énumération d'adresses e-mail.

Modèle d'e-mail par défaut pour la connexion par lien

Le modèle d'e-mail par défaut inclut un code temporel dans l'objet et le corps de l'e-mail afin que les e-mails suivants ne soient pas regroupés dans un même fil de discussion et que le lien ne soit pas masqué.

Ce modèle s'applique aux langues suivantes :

Code Langue
ar Arabe
zh-CN Chinois (simplifié)
zh-TW Chinois (traditionnel)
nl Néerlandais
en Anglais
en-GB Anglais (Royaume-Uni)
fr Français
de Allemand
id Indonésien
pour les recevoir. Italien
ja Japonais
ko Coréen
pl Polonais
pt-BR Portugais (Brésil)
pt-PT Portugais (Portugal)
ru Russe
es Espagnol
es-419 Espagnol (Amérique latine)
th Thaï

Étapes suivantes

Lorsqu'un utilisateur se connecte pour la première fois, un nouvel utilisateur est créé et associé aux identifiants (nom d'utilisateur et mot de passe, numéro de téléphone ou informations du fournisseur d'authentification) avec lesquels il s'est connecté. Ce nouveau compte est stocké dans votre projet Firebase et peut être utilisé pour identifier un utilisateur dans toutes les applications de votre projet, quelle que soit la méthode de connexion de l'utilisateur.

  • Dans vos applications, la méthode recommandée pour connaître l'état d'authentification de votre utilisateur consiste à définir un observateur sur l'objet Auth. Vous pouvez ensuite obtenir les informations de profil de base de l'utilisateur à partir de l'objet User. Consultez Gérer les utilisateurs.

  • Dans vos Firebase Realtime Database et Cloud Storage Règles de sécurité, vous pouvez obtenir l'ID utilisateur unique de l'utilisateur connecté à partir de la variable auth, et l'utiliser pour contrôler les données auxquelles un utilisateur peut accéder.

Vous pouvez autoriser les utilisateurs à se connecter à votre application à l'aide de plusieurs fournisseurs d'authentification en associant les identifiants du fournisseur d'authentification à un compte utilisateur existant.

Pour déconnecter un utilisateur, appelez signOut :

Web

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

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

Web

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});