Menautkan beberapa penyedia ke satu akun

Dokumen ini menunjukkan cara menautkan beberapa penyedia ke satu akun Identity Platform.

Identity Platform menggunakan ID unik untuk mengidentifikasi pengguna. Dengan begitu, pengguna bisa login ke akun yang sama dengan penyedia yang berbeda. Misalnya, pengguna yang awalnya mendaftar dengan nomor telepon dapat menautkan Akun Google-nya, lalu menggunakan salah satu metode tersebut untuk login.

Sebelum memulai

Tambahkan dukungan untuk dua penyedia identitas atau lebih ke aplikasi Anda.

Mengaktifkan atau menonaktifkan penautan akun

Setelan penautan akun menentukan cara Identity Platform menangani pengguna yang mencoba login dengan email yang sama menggunakan penyedia yang berbeda.

  • Tautkan akun yang menggunakan email yang sama: Identity Platform akan menimbulkan error jika pengguna mencoba login dengan email yang sudah digunakan. Aplikasi Anda dapat menangkap error ini, dan menautkan penyedia baru ke akun mereka yang sudah ada.

  • Buat beberapa akun untuk setiap penyedia identitas: Akun pengguna Identity Platform baru akan dibuat setiap kali pengguna login dengan penyedia yang berbeda.

Untuk memilih setelan:

  1. Buka halaman Settings Identity Platform di Konsol Google Cloud.

    Buka halaman Setelan

  2. Pilih setelan di bagian Penautan akun pengguna.

  3. Klik Save.

Menautkan kredensial penyedia gabungan

Untuk menautkan kredensial dari penyedia gabungan:

  1. Proses login pengguna dengan penyedia atau metode autentikasi apa pun.

  2. Dapatkan objek penyedia yang sesuai dengan penyedia yang ingin Anda tautkan dengan akun pengguna. Contoh:

    Web versi 9

    import { GoogleAuthProvider, FacebookAuthProvider, TwitterAuthProvider, GithubAuthProvider } from "firebase/auth";
    
    const googleProvider = new GoogleAuthProvider();
    const facebookProvider = new FacebookAuthProvider();
    const twitterProvider = new TwitterAuthProvider();
    const githubProvider = new GithubAuthProvider();

    Web versi 8

    var googleProvider = new firebase.auth.GoogleAuthProvider();
    var facebookProvider = new firebase.auth.FacebookAuthProvider();
    var twitterProvider = new firebase.auth.TwitterAuthProvider();
    var githubProvider = new firebase.auth.GithubAuthProvider();
  3. Mintalah pengguna untuk login dengan penyedia yang ingin Anda tautkan. Anda dapat membuka jendela pop-up atau mengalihkan halaman saat ini. Pengalihan akan lebih mudah bagi pengguna di perangkat seluler.

    Untuk menampilkan pop-up, panggil linkWithPopup():

    Web versi 9

    import { getAuth, linkWithPopup, GoogleAuthProvider } from "firebase/auth";
    const provider = new GoogleAuthProvider();
    
    const auth = getAuth();
    linkWithPopup(auth.currentUser, provider).then((result) => {
      // Accounts successfully linked.
      const credential = GoogleAuthProvider.credentialFromResult(result);
      const user = result.user;
      // ...
    }).catch((error) => {
      // Handle Errors here.
      // ...
    });

    Web versi 8

    auth.currentUser.linkWithPopup(provider).then((result) => {
      // Accounts successfully linked.
      var credential = result.credential;
      var user = result.user;
      // ...
    }).catch((error) => {
      // Handle Errors here.
      // ...
    });

    Untuk mengalihkan halaman, panggil linkWithRedirect() terlebih dahulu:

    Ikuti praktik terbaik saat menggunakan signInWithRedirect, linkWithRedirect, atau reauthenticateWithRedirect.

    Web versi 9

    import { getAuth, linkWithRedirect, GoogleAuthProvider } from "firebase/auth";
    const provider = new GoogleAuthProvider();
    
    const auth = getAuth();
    linkWithRedirect(auth.currentUser, provider)
      .then(/* ... */)
      .catch(/* ... */);

    Web versi 8

    auth.currentUser.linkWithRedirect(provider)
      .then(/* ... */)
      .catch(/* ... */);

    Setelah pengguna login, mereka akan dialihkan kembali ke aplikasi Anda. Kemudian, Anda dapat mengambil hasil login dengan memanggil getRedirectResult():

    Web versi 9

    import { getRedirectResult } from "firebase/auth";
    getRedirectResult(auth).then((result) => {
      const credential = GoogleAuthProvider.credentialFromResult(result);
      if (credential) {
        // Accounts successfully linked.
        const user = result.user;
        // ...
      }
    }).catch((error) => {
      // Handle Errors here.
      // ...
    });

    Web versi 8

    auth.getRedirectResult().then((result) => {
      if (result.credential) {
        // Accounts successfully linked.
        var credential = result.credential;
        var user = result.user;
        // ...
      }
    }).catch((error) => {
      // Handle Errors here.
      // ...
    });

Akun pengguna dengan penyedia gabungan kini ditautkan ke akun Identity Platform mereka, dan pengguna tersebut dapat menggunakan penyedia tersebut untuk login.

Menautkan kredensial email dan sandi

Untuk menambahkan alamat email dan sandi ke akun pengguna yang ada:

  1. Proses login pengguna dengan penyedia atau metode identitas apa pun.

  2. Mintalah pengguna mengisi alamat email dan sandi.

  3. Buat objek AuthCredential dengan alamat email dan sandi tersebut:

    Web versi 9

    import { EmailAuthProvider } from "firebase/auth";
    
    const credential = EmailAuthProvider.credential(email, password);

    Web versi 8

    var credential = firebase.auth.EmailAuthProvider.credential(email, password);
  4. Teruskan objek AuthCredential ke metode linkWithCredential() pada pengguna yang login:

    Web versi 9

    import { getAuth, linkWithCredential } from "firebase/auth";
    
    const auth = getAuth();
    linkWithCredential(auth.currentUser, credential)
      .then((usercred) => {
        const user = usercred.user;
        console.log("Account linking success", user);
      }).catch((error) => {
        console.log("Account linking error", error);
      });

    Web versi 8

    auth.currentUser.linkWithCredential(credential)
      .then((usercred) => {
        var user = usercred.user;
        console.log("Account linking success", user);
      }).catch((error) => {
        console.log("Account linking error", error);
      });

Kredensial email dan sandi sekarang ditautkan ke akun Identity Platform pengguna, dan mereka dapat menggunakannya untuk login.

Perlu diketahui bahwa kredensial penyedia gabungan dapat ditautkan ke akun email/sandi dengan email yang berbeda. Jika hal ini terjadi, email yang sesuai dengan penyedia gabungan dapat digunakan untuk membuat akun email/sandi terpisah.

Menangani error account-exists-with-different-credential

Jika Anda mengaktifkan setelan Tautkan akun yang menggunakan email yang sama di Konsol Google Cloud, saat pengguna mencoba login ke penyedia (seperti SAML) dengan email yang sudah ada untuk penyedia lain (seperti Google), error auth/account-exists-with-different-credential akan muncul (beserta objek AuthCredential).

Untuk menangani error ini, minta pengguna untuk login dengan penyedia yang ada. Lalu, panggil linkWithCredential(), linkWithPopup(), atau linkWithRedirect() untuk mengaitkan penyedia baru ke akunnya menggunakan AuthCredential.

Contoh berikut menunjukkan cara menangani error ini saat pengguna mencoba login menggunakan Facebook:

Web versi 9

  import { signInWithPopup, signInWithEmailAndPassword, linkWithCredential } from "firebase/auth";

  // User tries to sign in with Facebook.
  signInWithPopup(auth, facebookProvider).catch((error) => {
  // User's email already exists.
  if (error.code === 'auth/account-exists-with-different-credential') {
    // The pending Facebook credential.
    const pendingCred = error.credential;
    // The provider account's email address.
    const email = error.customData.email;

    // Present the user with a list of providers they might have
    // used to create the original account.
    // Then, ask the user to sign in with the existing provider.
    const method = promptUserForSignInMethod();

    if (method === 'password') {
      // TODO: Ask the user for their password.
      // In real scenario, you should handle this asynchronously.
      const password = promptUserForPassword();
      signInWithEmailAndPassword(auth, email, password).then((result) => {
        return linkWithCredential(result.user, pendingCred);
      }).then(() => {
        // Facebook account successfully linked to the existing user.
        goToApp();
      });
      return;
    }

    // All other cases are external providers.
    // Construct provider object for that provider.
    // TODO: Implement getProviderForProviderId.
    const provider = getProviderForProviderId(method);
    // At this point, you should let the user know that they already have an
    // account with a different provider, and validate they want to sign in
    // with the new provider.
    // Note: Browsers usually block popups triggered asynchronously, so in
    // real app, you should ask the user to click on a "Continue" button
    // that will trigger signInWithPopup().
    signInWithPopup(auth, provider).then((result) => {
      // Note: Identity Platform doesn't control the provider's sign-in
      // flow, so it's possible for the user to sign in with an account
      // with a different email from the first one.

      // Link the Facebook credential. We have access to the pending
      // credential, so we can directly call the link method.
      linkWithCredential(result.user, pendingCred).then((userCred) => {
        // Success.
        goToApp();
      });
    });
  }
});

Web versi 8

  // User tries to sign in with Facebook.
      auth.signInWithPopup(facebookProvider).catch((error) => {
  // User's email already exists.
  if (error.code === 'auth/account-exists-with-different-credential') {
    // The pending Facebook credential.
    const pendingCred = error.credential;
    // The provider account's email address.
    const email = error.email;

    // Present the user with a list of providers they might have
    // used to create the original account.
    // Then, ask the user to sign in with the existing provider.
    const method = promptUserForSignInMethod();

    if (method === 'password') {
      // TODO: Ask the user for their password.
      // In real scenario, you should handle this asynchronously.
      const password = promptUserForPassword();
      auth.signInWithEmailAndPassword(email, password).then((result) => {
        return result.user.linkWithCredential(pendingCred);
      }).then(() => {
        // Facebook account successfully linked to the existing user.
        goToApp();
      });
      return;
    }

    // All other cases are external providers.
    // Construct provider object for that provider.
    // TODO: Implement getProviderForProviderId.
    const provider = getProviderForProviderId(method);
    // At this point, you should let the user know that they already have an
    // account with a different provider, and validate they want to sign in
    // with the new provider.
    // Note: Browsers usually block popups triggered asynchronously, so in
    // real app, you should ask the user to click on a "Continue" button
    // that will trigger signInWithPopup().
    auth.signInWithPopup(provider).then((result) => {
      // Note: Identity Platform doesn't control the provider's sign-in
      // flow, so it's possible for the user to sign in with an account
      // with a different email from the first one.

      // Link the Facebook credential. We have access to the pending
      // credential, so we can directly call the link method.
      result.user.linkWithCredential(pendingCred).then((userCred) => {
        // Success.
        goToApp();
      });
    });
  }
});

Menggunakan pengalihan mirip dengan pop-up, tetapi Anda harus meng-cache kredensial yang tertunda di antara pengalihan halaman (misalnya, dengan menggunakan penyimpanan sesi).

Perlu diperhatikan bahwa beberapa penyedia layanan, seperti Google dan Microsoft, berfungsi sebagai penyedia identitas sosial dan email. Penyedia email dianggap otoritatif untuk semua alamat yang terkait dengan domain email yang dihosting. Artinya, pengguna yang login dengan alamat email yang dihosting oleh penyedia yang sama tidak akan pernah melaporkan error ini (misalnya, login dengan Google menggunakan email @gmail.com, atau Microsoft menggunakan email @live.com atau @outlook.com).

Menggabungkan akun secara manual

Jika pengguna mencoba login dengan kredensial yang sudah ditautkan ke akun pengguna lain menggunakan penyedia yang sama, metode bawaan SDK Klien untuk penautan akun akan gagal. Dalam situasi ini, Anda harus menggabungkan akun secara manual, lalu menghapus akun kedua. Contoh:

Web versi 9

// Sign in first account.
const result1 = await signInWithCredential(auth, cred1);
const user1 = result1.user;
// Try to link a credential that belongs to an existing account
try {
  await linkWithCredential(user1, cred2);
} catch (error) {
  // cred2 already exists so an error is thrown.
  const result2 = await signInWithCredential(auth, error.credential);
  const user2 = result2.user;
  // Merge the data.
  mergeData(user1, user2);
  // Delete one of the accounts, and try again.
  await user2.delete();
  // Linking now will work.
  await linkWithCredential(user1, result2.credential);
}

Web versi 8

// Sign in first account.
const result1 = await auth.signInWithCredential(cred1);
const user1 = result1.user;
// Try to link a credential that belongs to an existing account
try {
  await user1.linkWithCredential(cred2);
} catch (error) {
  // cred2 already exists so an error is thrown.
  const result2 = await auth.signInWithCredential(error.credential);
  const user2 = result2.user;
  // Merge the data.
  mergeData(user1, user2);
  // Delete one of the accounts, and try again.
  await user2.delete();
  // Linking now will work.
  await user1.linkWithCredential(result2.credential);
}

Anda dapat membatalkan tautan penyedia dari akun pengguna. Pengguna tidak akan dapat lagi melakukan autentikasi dengan penyedia tersebut.

Untuk membatalkan tautan penyedia, teruskan ID penyedia ke metode unlink(). Anda bisa mendapatkan ID penyedia autentikasi yang tertaut dengan pengguna dari properti providerData.

Web versi 9

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

const auth = getAuth();
unlink(auth.currentUser, providerId).then(() => {
  // Auth provider unlinked from account
  // ...
}).catch((error) => {
  // An error happened
  // ...
});

Web versi 8

user.unlink(providerId).then(() => {
  // Auth provider unlinked from account
  // ...
}).catch((error) => {
  // An error happened
  // ...
});

Langkah selanjutnya