Esegui l'autenticazione con Firebase utilizzando il link email in JavaScript

Puoi utilizzare Firebase Authentication per far accedere un utente inviandogli un'email contenente un link su cui può fare clic per accedere. Durante la procedura, viene verificato anche l'indirizzo email dell'utente.

L'accesso via email offre numerosi vantaggi:

  • Registrazione e accesso senza problemi.
  • Ridurre il rischio di riutilizzo delle password tra le applicazioni, il che può minare la sicurezza anche delle password ben selezionate.
  • La possibilità di autenticare un utente e di verificare al contempo che sia il proprietario legittimo di un indirizzo email.
  • Per accedere, un utente deve disporre solo di un account email accessibile. Non è richiesta la proprietà di un numero di telefono o di un account di social media.
  • Un utente può accedere in sicurezza senza dover fornire (o ricordare) una password, il che può essere complicato su un dispositivo mobile.
  • Per un utente esistente che in precedenza ha eseguito l'accesso con un identificatore email (password o federato), è possibile eseguire l'upgrade in modo che possa accedere solo con l'email. Ad esempio, un utente che ha dimenticato la password può comunque accedere senza doverla reimpostare.

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 progetto JavaScript.

Per consentire agli utenti di accedere tramite link email, devi prima attivare il provider email e il metodo di accesso tramite link email per il tuo progetto Firebase:

  1. Nella console Firebase, apri la sezione Auth.
  2. Nella scheda Metodo di accesso, attiva il provider Email/Password. Tieni presente che per utilizzare l'accesso tramite link email è necessario attivare l'accesso tramite email/password.
  3. Nella stessa sezione, attiva il metodo di accesso Link via email (accesso senza password).
  4. Fai clic su Salva.

Per avviare il flusso di autenticazione, presenta all'utente un'interfaccia che lo invita a fornire il proprio indirizzo email, quindi chiama sendSignInLinkToEmail per richiedere a Firebase di inviare il link di autenticazione all'indirizzo email dell'utente.

  1. Costruisci l'oggetto ActionCodeSettings, che fornisce a Firebase le istruzioni su come creare il link email. Imposta i seguenti campi:

    • url: il link diretto da incorporare e qualsiasi stato aggiuntivo da trasmettere. Il dominio del link deve essere aggiunto all'elenco dei domini autorizzati della console Firebase, che puoi trovare nella scheda Metodo di accesso (Autenticazione -> Impostazioni).
    • android e ios: aiutano Firebase Authentication a determinare se deve creare un link solo per il web o per il mobile che si apre su un dispositivo Android o Apple.
    • handleCodeInApp: impostato su true. L'operazione di accesso deve sempre essere completata nell'app, a differenza di altre azioni via email out of band (reimpostazione della password e verifiche email). Questo perché, alla fine del flusso, si presume che l'utente abbia eseguito l'accesso e che il suo stato di autenticazione sia stato mantenuto all'interno dell'app.
    • linkDomain: quando sono definiti domini di link Hosting personalizzati per un progetto, specifica quale utilizzare quando il link deve essere aperto da un'app mobile specificata. In caso contrario, viene selezionato automaticamente il dominio predefinito (ad es. PROJECT_ID.firebaseapp.com).
    • dynamicLinkDomain: deprecato. Non specificare questo parametro.

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

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

    Per saperne di più su ActionCodeSettings, consulta la sezione Passare lo stato nelle azioni email.

  2. Chiedi all'utente il suo indirizzo email.

  3. Invia il link di autenticazione all'indirizzo email dell'utente e salvalo nel caso in cui l'utente completi l'accesso via email sullo stesso dispositivo.

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

Problemi di sicurezza

Per impedire che un link di accesso venga utilizzato per accedere come utente non previsto o su un dispositivo non previsto, Firebase Auth richiede di fornire l'indirizzo email dell'utente al termine del flusso di accesso. Affinché l'accesso vada a buon fine, questo indirizzo email deve corrispondere a quello a cui è stato inviato originariamente il link di accesso.

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

Al termine dell'accesso, qualsiasi meccanismo di accesso non verificato precedente verrà rimosso dall'utente e le sessioni esistenti verranno invalidate. Ad esempio, se qualcuno ha creato in precedenza un account non verificato con la stessa email e la stessa password, la password dell'utente verrà rimossa per impedire all'usurpatore che ha rivendicato la proprietà e creato l'account non verificato di accedere di nuovo con l'email e la password non verificate.

Inoltre, assicurati di utilizzare un URL HTTPS in produzione per evitare che il link venga potenzialmente intercettato da server intermedi.

Completare l'accesso in una pagina web

Il formato del link diretto all'email è lo stesso del formato utilizzato per le azioni email out of band (verifica email, reimpostazione della password e revoca della modifica email). Firebase Auth semplifica questo controllo fornendo l'API isSignInWithEmailLink per verificare se un link è un link di accesso con indirizzo email.

Per completare l'accesso nella pagina di destinazione, chiama signInWithEmailLink fornendo l'email dell'utente e il link all'email contenente il codice una tantum.

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

Completare l'accesso in un'app mobile

Firebase Authentication utilizza Firebase Hosting per inviare il link email a un dispositivo mobile. Per completare l'accesso tramite l'applicazione mobile, l'applicazione deve essere configurata per rilevare il link dell'applicazione in arrivo, analizzare il link diretto sottostante e completare l'accesso come avviene tramite il flusso web.

Per scoprire di più su come gestire l'accesso con il link email in un'applicazione Android, consulta la guida per Android.

Per scoprire di più su come gestire l'accesso con il link email in un'applicazione Apple, consulta la guida alle piattaforme Apple.

Puoi anche collegare questo metodo di autenticazione a un utente esistente. Ad esempio, un utente che si è autenticato in precedenza con un altro fornitore, ad esempio un numero di telefono, può aggiungere questo metodo di accesso al proprio account esistente.

La differenza si trova nella seconda metà dell'operazione:

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

Può essere utilizzato anche per autenticare di nuovo un utente con link email prima di eseguire un'operazione sensibile.

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

Tuttavia, poiché il flusso potrebbe terminare su un altro dispositivo su cui l'utente originale non ha eseguito l'accesso, questo flusso potrebbe non essere completato. In questo caso, all'utente può essere mostrato un messaggio di errore per costringerlo ad aprire il link sullo stesso dispositivo. Nel link è possibile specificare un valore per fornire informazioni sul tipo di operazione e sull'UID dell'utente.

Se hai creato il progetto a partire dal 15 settembre 2023, la protezione dall'enumerazione email è abilitata per impostazione predefinita. Questa funzionalità migliora la sicurezza degli account utente del progetto, ma disattiva il metodo fetchSignInMethodsForEmail(), che in precedenza consigliavamo per implementare i flussi che danno la priorità all'identificatore.

Sebbene tu possa disattivare la protezione da enumerazione email per il tuo progetto, non lo consigliamo.

Per ulteriori dettagli, consulta la documentazione sulla protezione dall'enumerazione delle email.

Modello email predefinito per l'accesso tramite link

Il modello 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 link nascosto.

Questo modello si applica alle seguenti lingue:

Codice Lingua
ar Arabo
zh-CN Cinese (semplificato)
zh-TW Cinese (tradizionale)
nl Olandese
it Inglese
en-GB Inglese (UK)
fr Francese
de Tedesco
id Indonesiano
che li ricevano. Italiano
ja Giapponese
ko Coreano
pl Polacco
pt-BR Portoghese (Brasile)
pt-PT Portoghese (Portogallo)
Russo Russo
es Spagnolo
es-419 Spagnolo (America Latina)
° Tailandese

Passaggi successivi

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 del fornitore di autenticazione, con cui l'utente ha eseguito l'accesso. Questo nuovo account viene archiviato nel tuo progetto Firebase e può essere utilizzato per identificare un utente in tutte le app del progetto, indipendentemente da come accede.

  • Nelle tue app, il modo consigliato per conoscere lo stato di autenticazione dell'utente è impostare un osservatore sull'oggetto Auth. Puoi quindi recuperare le informazioni di base del profilo dell'utente dall'oggetto User. Vedi Gestire gli utenti.

  • Nelle Regole di sicurezza Firebase Realtime Database e Cloud Storage, puoi recuperare l'ID utente univoco dell'utente che ha eseguito 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 scollegare un utente, chiama 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.
});