Autenticazione con Firebase utilizzando il collegamento e-mail in JavaScript

Puoi utilizzare l'autenticazione Firebase per accedere a un utente inviandogli un'e-mail contenente un collegamento su cui può fare clic per accedere. Durante il processo, viene verificato anche l'indirizzo e-mail dell'utente.

I vantaggi derivanti dall'accesso via e-mail sono numerosi:

  • Iscrizione e accesso a basso attrito.
  • Minore rischio di riutilizzo delle password tra le applicazioni, che può compromettere la sicurezza anche di password ben selezionate.
  • La capacità di autenticare un utente verificando anche che l'utente sia il legittimo proprietario di un indirizzo email.
  • Un utente necessita solo di un account e-mail accessibile per accedere. Non è richiesta la proprietà di un numero di telefono o di un account di social media.
  • Un utente può accedere in modo sicuro senza la necessità di fornire (o ricordare) una password, il che può risultare complicato su un dispositivo mobile.
  • Un utente esistente che ha effettuato l'accesso in precedenza con un identificatore di posta elettronica (password o federato) può essere aggiornato per accedere solo con l'e-mail. Ad esempio, un utente che ha dimenticato la password può comunque accedere senza dover reimpostarla.

Prima di iniziare

Se non l'hai già fatto, copia lo snippet di inizializzazione dalla console Firebase al tuo progetto come descritto in Aggiungere Firebase al tuo progetto JavaScript .

Per accedere agli utenti tramite collegamento e-mail, devi prima abilitare il metodo di accesso Provider e-mail e Collegamento e-mail per il tuo progetto Firebase:

  1. Nella console Firebase , apri la sezione Autenticazione .
  2. Nella scheda Metodo di accesso , abilita il provider di posta elettronica/password . Tieni presente che l'accesso tramite posta elettronica/password deve essere abilitato per utilizzare l'accesso tramite collegamento tramite posta elettronica.
  3. Nella stessa sezione, abilita il metodo di accesso Collegamento e-mail (accesso senza password) .
  4. Fare clic su Salva .

Per avviare il flusso di autenticazione, presentare all'utente un'interfaccia che richiede all'utente di fornire il proprio indirizzo e-mail e quindi chiamare sendSignInLinkToEmail per richiedere che Firebase invii il collegamento di autenticazione all'e-mail dell'utente.

  1. Costruisci l'oggetto ActionCodeSettings , che fornisce a Firebase le istruzioni su come costruire il collegamento e-mail. Imposta i seguenti campi:

    • url : il collegamento diretto da incorporare e qualsiasi stato aggiuntivo da trasmettere. Il dominio del collegamento deve essere aggiunto all'elenco dei domini autorizzati della Console Firebase, che può essere trovato accedendo alla scheda Metodo di accesso (Autenticazione -> Impostazioni).
    • android e ios : le app da utilizzare quando viene aperto il collegamento di accesso su un dispositivo Android o Apple. Scopri di più su come configurare Firebase Dynamic Links per aprire i collegamenti alle azioni e-mail tramite app mobili.
    • handleCodeInApp : impostato su true. L'operazione di accesso deve essere sempre completata nell'app a differenza di altre azioni e-mail fuori banda (reimpostazione della password e verifiche e-mail). Questo perché, alla fine del flusso, è previsto che l'utente abbia effettuato l'accesso e che il suo stato di autenticazione sia persistente all'interno dell'app.
    • dynamicLinkDomain : quando per un progetto vengono definiti più domini di collegamento dinamico personalizzati, specificare quale utilizzare quando il collegamento deve essere aperto tramite un'app mobile specificata (ad esempio, example.page.link ). Altrimenti verrà selezionato automaticamente il primo dominio.

      Web modular API

      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'
        },
        dynamicLinkDomain: 'example.page.link'
      };

      Web namespaced API

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

    Per ulteriori informazioni su ActionCodeSettings, fare riferimento alla sezione Stato di passaggio nelle azioni e-mail .

  2. Chiedi all'utente la sua email.

  3. Invia il collegamento di autenticazione all'e-mail dell'utente e salva l'e-mail dell'utente nel caso in cui l'utente completi l'accesso tramite e-mail sullo stesso dispositivo.

    Web modular API

    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 namespaced API

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

Problemi di sicurezza

Per impedire che un collegamento di accesso venga utilizzato per accedere come utente non previsto o su un dispositivo non previsto, Firebase Auth richiede che venga fornito l'indirizzo email dell'utente al completamento del flusso di accesso. Affinché l'accesso abbia esito positivo, questo indirizzo e-mail deve corrispondere all'indirizzo a cui è stato originariamente inviato il collegamento di accesso.

Puoi semplificare questo flusso per gli utenti che aprono il collegamento di accesso sullo stesso dispositivo su cui richiedono il collegamento, memorizzando il loro indirizzo email localmente, ad esempio utilizzando localStorage o i cookie, quando invii l'email di accesso. Quindi, utilizza questo indirizzo per completare il flusso. Non passare l'e-mail dell'utente nei parametri dell'URL di reindirizzamento e riutilizzarla poiché ciò potrebbe consentire iniezioni di sessione.

Una volta completato l'accesso, qualsiasi meccanismo di accesso precedente non verificato verrà rimosso dall'utente e tutte le sessioni esistenti verranno invalidate. Ad esempio, se qualcuno ha creato in precedenza un account non verificato con la stessa email e password, la password dell'utente verrà rimossa per impedire al sosia che ha rivendicato la proprietà e creato l'account non verificato di accedere nuovamente con email e password non verificate.

Assicurati inoltre di utilizzare un URL HTTPS in produzione per evitare che il tuo collegamento venga potenzialmente intercettato da server intermedi.

Completamento dell'accesso a una pagina Web

Il formato del collegamento diretto del collegamento e-mail è lo stesso del formato utilizzato per le azioni e-mail fuori banda (verifica dell'e-mail, reimpostazione della password e revoca della modifica dell'e-mail). Firebase Auth semplifica questo controllo fornendo l'API isSignInWithEmailLink per verificare se un collegamento è un accesso con collegamento e-mail.

Per completare l'accesso alla pagina di destinazione, chiama signInWithEmailLink con l'e-mail dell'utente e il collegamento e-mail effettivo contenente il codice monouso.

Web modular API

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

Web namespaced API

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

Completamento dell'accesso in un'app mobile

L'autenticazione Firebase utilizza Firebase Dynamic Links per inviare il collegamento e-mail a un dispositivo mobile. Per completare l'accesso tramite l'applicazione mobile, l'applicazione deve essere configurata per rilevare il collegamento dell'applicazione in ingresso, analizzare il collegamento profondo sottostante e quindi completare l'accesso come avviene tramite il flusso web.

Per saperne di più su come gestire l'accesso con collegamento email in un'applicazione Android, fare riferimento alla guida Android .

Per ulteriori informazioni su come gestire l'accesso con il collegamento e-mail in un'applicazione Apple, fare riferimento alla guida alle piattaforme Apple .

Puoi anche collegare questo metodo di autenticazione a un utente esistente. Ad esempio, un utente precedentemente autenticato con un altro provider, ad esempio un numero di telefono, può aggiungere questo metodo di accesso al proprio account esistente.

La differenza sarebbe nella seconda metà dell’operazione:

Web modular API

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 namespaced API

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

Può essere utilizzato anche per autenticare nuovamente un utente con collegamento e-mail prima di eseguire un'operazione sensibile.

Web modular API

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 namespaced API

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

Tuttavia, poiché il flusso potrebbe finire su un dispositivo diverso su cui l'utente originale non ha effettuato l'accesso, questo flusso potrebbe non essere completato. In tal caso, è possibile mostrare all'utente un errore per costringerlo ad aprire il collegamento sullo stesso dispositivo. Alcuni stati possono essere passati nel collegamento per fornire informazioni sul tipo di operazione e sull'uid dell'utente.

Se hai creato il tuo progetto a partire dal 15 settembre 2023, la protezione dell'enumerazione dei messaggi di posta elettronica è abilitata per impostazione predefinita. Questa funzionalità migliora la sicurezza degli account utente del tuo progetto, ma disabilita il metodo fetchSignInMethodsForEmail() , che in precedenza consigliavamo per implementare i flussi incentrati sull'identificatore.

Anche se puoi disabilitare la protezione dell'enumerazione delle email per il tuo progetto, ti consigliamo di non farlo.

Per ulteriori dettagli, consultare la documentazione sulla protezione dell'enumerazione della posta elettronica .

Modello di posta elettronica predefinito per l'accesso tramite collegamento

Il modello di email predefinito include un timestamp nell'oggetto e nel corpo dell'email in modo che le email successive non vengano compresse in un unico thread, con il collegamento che viene nascosto .

Questo modello si applica alle seguenti lingue:

Codice Lingua
ar Arabo
zh-CN Cinese semplificato)
zh-TW Cinese tradizionale)
n.l Olandese
en Inglese
it-GB Inglese (Regno Unito)
fr francese
de Tedesco
id indonesiano
Esso Italiano
giapponese
ko coreano
per favore Polacco
pt-BR Portoghese (Brasile)
pt-PT Portoghese (Portogallo)
ru russo
es spagnolo
es-419 Spagnolo (America Latina)
th tailandese

Prossimi passi

Dopo che un utente accede per la prima volta, viene creato un nuovo account utente e collegato alle credenziali, ovvero nome utente e password, numero di telefono o informazioni sul provider di autenticazione, con cui l'utente ha effettuato l'accesso. Questo nuovo account viene archiviato come parte del tuo progetto Firebase e può essere utilizzato per identificare un utente in ogni app del tuo progetto, indipendentemente dalla modalità di accesso dell'utente.

  • Nelle tue app, il modo consigliato per conoscere lo stato di autenticazione del tuo utente è impostare un osservatore sull'oggetto Auth . È quindi possibile ottenere le informazioni di base del profilo dell'utente dall'oggetto User . Vedi Gestisci utenti .

  • Nel tuo Firebase Realtime Database e Cloud Storage Security Rules , puoi ottenere l'ID utente univoco dell'utente che ha effettuato l'accesso dalla variabile auth e utilizzarlo per controllare a quali dati può accedere un utente.

Puoi consentire agli utenti di accedere alla tua app utilizzando più provider di autenticazione collegando le credenziali del provider di autenticazione a un account utente esistente.

Per disconnettere un utente, chiamare signOut :

Web modular API

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

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

Web namespaced API

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