Melakukan Autentikasi dengan Firebase Menggunakan Link Email

Anda dapat menggunakan Firebase Authentication untuk membuat pengguna login dengan mengirimkan email yang berisi link, yang dapat mereka klik untuk login. Dalam prosesnya, alamat email pengguna juga akan diverifikasi.

Ada banyak manfaat login dengan email:

  • Proses pendaftaran dan login lebih lancar.
  • Risiko penggunaan ulang sandi lintas aplikasi lebih rendah. Penggunaan sandi yang sama dapat mengurangi keamanan, sekalipun sandi sudah dipilih dengan baik.
  • Dapat mengautentikasi pengguna, sekaligus memverifikasi bahwa pengguna adalah pemilik sah alamat email.
  • Pengguna hanya memerlukan akun email yang dapat diakses untuk login. Tidak diperlukan kepemilikan akun media sosial atau nomor telepon.
  • Pengguna dapat login dengan aman tanpa perlu memasukkan (atau mengingat) sandi, yang bisa merepotkan pada perangkat seluler.
  • Pengguna yang sudah ada dan pernah login dengan ID email (sandi atau penyedia identitas gabungan) dapat diupgrade agar bisa login dengan email saja. Misalnya, pengguna yang lupa sandi masih dapat login tanpa perlu mereset sandinya.

Sebelum memulai

  1. Jika Anda belum melakukannya, ikuti langkah-langkah di panduan Memulai.

  2. Aktifkan metode login dengan Link Email untuk project Firebase.

    Untuk memproses login dengan melalui link email, Anda harus terlebih dahulu mengaktifkan metode login dengan Penyedia email dan Link email untuk project Firebase Anda:

    1. Di Firebase console, buka bagian Auth.
    2. Pada tab Sign-in method, aktifkan penyedia Email/Password. Perlu diketahui bahwa login dengan email/sandi harus diaktifkan untuk menggunakan metode login dengan link email.
    3. Di bagian yang sama, aktifkan metode login dengan Email link (passwordless sign-in).
    4. Klik Save.

Untuk memulai alur autentikasi, tampilkan antarmuka yang akan meminta pengguna memberikan alamat email, lalu panggil sendSignInLinkToEmail() untuk meminta Firebase mengirimkan link autentikasi ke email pengguna.

  1. Buat objek ActionCodeSettings yang akan memberi Firebase petunjuk mengenai cara membuat link email. Tetapkan kolom berikut:

    • url: Deep link yang akan disematkan dan semua status tambahan yang akan diteruskan. Domain link harus ditambahkan dalam daftar domain yang diizinkan di Firebase Console, yang dapat ditemukan dengan membuka tab Sign-in method (Authentication -> Sign-in method). Link tersebut akan mengalihkan pengguna ke URL ini apabila aplikasi tidak terinstal di perangkat pengguna dan aplikasi tidak dapat diinstal.

    • androidPackageName dan IOSBundleId: Aplikasi yang akan digunakan saat link login dibuka di perangkat Android atau iOS. Pelajari lebih lanjut cara mengonfigurasi Firebase Dynamic Links untuk membuka link tindakan email melalui aplikasi seluler.

    • Tetapkan handleCodeInApp ke true. Operasi login harus selalu diselesaikan di aplikasi, tidak seperti tindakan eksternal terkait email yang lain (reset sandi dan verifikasi email). Hal ini perlu dilakukan karena di akhir alur, pengguna diharapkan sudah login dan status Auth-nya tersimpan di dalam aplikasi.

    • dynamicLinkDomain: Jika beberapa domain link dinamis kustom ditetapkan untuk suatu project, tentukan domain yang akan digunakan ketika link dibuka melalui aplikasi seluler tertentu (misalnya, example.page.link). Jika tidak ada yang ditentukan, domain pertama akan dipilih secara otomatis.

    var acs = ActionCodeSettings(
        // URL you want to redirect back to. The domain (www.example.com) for this
        // URL must be whitelisted in the Firebase Console.
        url: 'https://www.example.com/finishSignUp?cartId=1234',
        // This must be true
        handleCodeInApp: true,
        iOSBundleId: 'com.example.ios',
        androidPackageName: 'com.example.android',
        // installIfNotAvailable
        androidInstallApp: true,
        // minimumVersion
        androidMinimumVersion: '12');
    
  2. Minta pengguna memberikan alamat emailnya.

  3. Kirim link autentikasi ke email pengguna, dan simpan email tersebut untuk berjaga-jaga jika pengguna menyelesaikan proses login dengan email pada perangkat yang sama.

    var emailAuth = 'someemail@domain.com';
    FirebaseAuth.instance.sendSignInLinkToEmail(
            email: emailAuth, actionCodeSettings: acs)
        .catchError((onError) => print('Error sending email verification $onError'))
        .then((value) => print('Successfully sent email verification'));
    });
    

Masalah keamanan

Demi mencegah penggunaan link login untuk login sebagai pengguna yang tidak dimaksud atau pada perangkat yang tidak dimaksud, Firebase Auth mengharuskan pengguna memasukkan alamat emailnya saat menyelesaikan alur login. Agar proses login berhasil, alamat email ini harus sama dengan alamat yang awalnya dikirimi link login.

Anda dapat menyederhanakan alur ini untuk pengguna yang membuka link login di perangkat yang sama dengan yang digunakan untuk meminta link. Caranya adalah dengan menyimpan alamat emailnya secara lokal, misalnya menggunakan SharedPreferences, saat Anda mengirimkan email login. Kemudian, gunakan alamat ini untuk menyelesaikan alur. Jangan meneruskan dan menggunakan kembali alamat email pengguna dalam parameter URL alihan karena tindakan ini dapat mengaktifkan injeksi sesi.

Setelah proses login selesai, semua mekanisme login sebelumnya yang tidak diverifikasi akan dihapus dari pengguna dan semua sesi yang ada menjadi tidak valid. Misalnya, jika seseorang sebelumnya menggunakan email dan sandi yang sama untuk membuat akun yang tidak diverifikasi, sandi pengguna tersebut akan dihapus. Dengan begitu, peniru identitas yang mengklaim kepemilikan dan membuat akun yang tidak diverifikasi tersebut tidak akan dapat login lagi dengan email dan sandi yang tidak diverifikasi.

Selain itu, pastikan Anda menggunakan URL HTTPS dalam fase produksi agar link tidak ditangkap oleh server perantara.

Firebase Authentication menggunakan Firebase Dynamic Links untuk mengirim link email ke perangkat seluler. Untuk menyelesaikan proses login melalui aplikasi seluler, aplikasi harus dikonfigurasi untuk mendeteksi link aplikasi yang masuk, mengurai deep link yang mendasarinya, lalu menyelesaikan proses login.

  1. Siapkan aplikasi Anda untuk menerima Dynamic Links di Flutter dalam panduan.

  2. Di pengendali link, periksa apakah link tersebut dimaksudkan untuk autentikasi link email dan, jika ya, selesaikan proses login.

    // Confirm the link is a sign-in with email link.
    if (FirebaseAuth.instance.isSignInWithEmailLink(emailLink)) {
      try {
        // The client SDK will parse the code from the link for you.
        final userCredential = await FirebaseAuth.instance
            .signInWithEmailLink(email: emailAuth, emailLink: emailLink);
    
        // You can access the new user via userCredential.user.
        final emailAddress = userCredential.user?.email;
    
        print('Successfully signed in with email link!');
      } catch (error) {
        print('Error signing in with email link.');
      }
    }
    

Anda juga dapat menautkan metode autentikasi ini dengan pengguna yang sudah ada. Misalnya, pengguna yang sebelumnya diautentikasi dengan penyedia lain, seperti nomor telepon, dapat menambahkan metode login ini ke akunnya yang sudah ada.

Perbedaannya terletak pada paruh kedua operasi:

final authCredential = EmailAuthProvider
    .credentialWithLink(email: emailAuth, emailLink: emailLink.toString());
try {
    await FirebaseAuth.instance.currentUser
        ?.linkWithCredential(authCredential);
} catch (error) {
    print("Error linking emailLink credential.");
}

Metode ini juga dapat digunakan untuk mengautentikasi ulang pengguna link email sebelum menjalankan operasi yang sensitif.

final authCredential = EmailAuthProvider
    .credentialWithLink(email: emailAuth, emailLink: emailLink.toString());
try {
    await FirebaseAuth.instance.currentUser
        ?.reauthenticateWithCredential(authCredential);
} catch (error) {
    print("Error reauthenticating credential.");
}

Namun, karena alur ini dapat berakhir di perangkat berbeda yang tidak dipakai pengguna awal untuk login, alur ini mungkin tidak akan diselesaikan. Dalam hal ini, pesan error dapat ditampilkan sehingga pengguna harus membuka link di perangkat yang sama. Beberapa status dapat diteruskan di link untuk memberikan informasi tentang jenis operasi dan UID pengguna.

Jika Anda mendukung metode login dengan email berbasis sandi dan juga link, gunakan fetchSignInMethodsForEmail untuk membedakan kedua metode tersebut. Cara ini berguna dalam alur yang mendahulukan ID, yakni ketika pengguna diminta memasukkan emailnya terlebih dahulu sebelum metode login ditunjukkan kepadanya:

try {
    final signInMethods =
        await FirebaseAuth.instance.fetchSignInMethodsForEmail(emailAuth);
    final userExists = signInMethods.isNotEmpty;
    final canSignInWithLink = signInMethods
        .contains(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD);
    final canSignInWithPassword = signInMethods
        .contains(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD);
} on FirebaseAuthException catch (exception) {
    switch (exception.code) {
        case "invalid-email":
            print("Not a valid email address.");
            break;
        default:
            print("Unknown error.");
    }
}

Seperti yang dijelaskan di atas, email/sandi dan email/link dianggap sebagai EmailAuthProvider yang sama (PROVIDER_ID yang sama) dengan metode login yang berbeda.

Langkah berikutnya

Setelah pengguna membuat akun baru, akun ini akan disimpan sebagai bagian dari project Firebase Anda, dan dapat digunakan untuk mengidentifikasi pengguna di setiap aplikasi dalam project, terlepas dari metode login yang digunakan pengguna.

Di aplikasi, Anda bisa mendapatkan informasi profil dasar pengguna dari objek User. Baca bagian Mengelola Pengguna.

Di Aturan Keamanan Firebase Realtime Database dan Cloud Storage, Anda bisa mendapatkan ID pengguna unik milik pengguna yang login dari variabel auth, dan menggunakannya untuk mengontrol data apa saja yang dapat diakses oleh pengguna.

Anda dapat mengizinkan pengguna untuk login ke aplikasi menggunakan beberapa penyedia autentikasi dengan menautkan kredensial penyedia autentikasi) ke akun pengguna yang ada.

Untuk memproses logout pengguna, panggil signOut():

await FirebaseAuth.instance.signOut();