Melakukan Autentikasi dengan Firebase dengan Nomor Telepon Menggunakan JavaScript

Anda dapat menggunakan Firebase Authentication untuk membuat pengguna login dengan mengirim pesan SMS ke ponselnya. Selanjutnya, pengguna login menggunakan kode sekali pakai yang dikirimkan dalam pesan SMS.

Cara termudah untuk menambahkan login dengan nomor telepon ke aplikasi adalah menggunakan FirebaseUI, yang mencakup widget login drop-in yang mengimplementasikan proses login untuk login dengan nomor telepon serta login berbasis sandi dan gabungan. Dokumen ini berisi penjelasan mengenai cara mengimplementasikan proses login dengan nomor telepon menggunakan Firebase SDK.

Sebelum memulai

Jika belum melakukannya, salin cuplikan inisialisasi dari Firebase console ke project Anda seperti yang dijelaskan di bagian Menambahkan Firebase ke project JavaScript.

Masalah keamanan

Meskipun mudah, autentikasi hanya melalui nomor telepon kurang aman dibandingkan metode lain yang tersedia, karena nomor tersebut dapat berpindah tangan antarpengguna dengan mudah. Selain itu, pada perangkat yang memuat beberapa profil pengguna, setiap pengguna yang dapat menerima pesan SMS dapat login ke akun menggunakan nomor telepon perangkat tersebut.

Jika menggunakan fitur login dengan nomor telepon di aplikasi, Anda harus menawarkannya bersama metode login yang lebih aman, dan memberi tahu pengguna tentang kelemahan keamanan jika menggunakan metode login dengan nomor telepon.

Mengaktifkan login dengan Nomor Telepon untuk project Firebase

Untuk memproses login pengguna melalui SMS, Anda harus mengaktifkan metode login dengan Nomor Telepon untuk project Firebase terlebih dahulu:

  1. Di Firebase console, buka bagian Authentication.
  2. Di halaman Sign-in Method, aktifkan metode login dengan Phone Number.
  3. Pada halaman yang sama, jika domain yang akan menghosting aplikasi tidak tercantum di bagian domain pengalihan OAuth, tambahkan domain Anda.

Kuota permintaan login dengan nomor telepon di Firebase cukup tinggi, sehingga sebagian besar aplikasi tidak akan terpengaruh. Namun, jika perlu memproses login pengguna dalam jumlah yang sangat besar menggunakan autentikasi dengan nomor telepon, Anda mungkin harus mengupgrade paket harga. Lihat halaman paket harga.

Menyiapkan pemverifikasi reCAPTCHA

Sebelum dapat memproses login dengan nomor telepon pengguna, Anda harus menyiapkan pemverifikasi reCAPTCHA Firebase. Firebase menggunakan reCAPTCHA untuk mencegah penyalahgunaan, misalnya dengan memastikan bahwa permintaan verifikasi nomor telepon berasal dari salah satu domain yang diizinkan oleh aplikasi Anda.

Anda tidak perlu menyiapkan klien reCAPTCHA secara manual. Jika Anda menggunakan objek RecaptchaVerifier pada Firebase SDK, Firebase secara otomatis akan membuat dan menangani kunci dan secret klien yang diperlukan.

Objek RecaptchaVerifier mendukung reCAPTCHA tidak terlihat, yang sering kali dapat memverifikasi pengguna tanpa memerlukan tindakan apa pun dari pengguna, serta widget reCAPTCHA yang selalu mengharuskan interaksi pengguna agar verifikasi berhasil diselesaikan.

reCAPTCHA hasil render yang mendasari dapat dilokalkan sesuai preferensi pengguna dengan memperbarui kode bahasa di instance Auth sebelum merender reCAPTCHA. Pelokalan tersebut juga akan berlaku untuk pesan SMS berisi kode verifikasi yang dikirim ke pengguna.

API modular web

import { getAuth } from "firebase/auth";

const auth = getAuth();
auth.languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// auth.useDeviceLanguage();

API dengan namespace web

firebase.auth().languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// firebase.auth().useDeviceLanguage();

Menggunakan reCAPTCHA tidak terlihat

Untuk menggunakan reCAPTCHA tidak terlihat, buat objek RecaptchaVerifier dengan menetapkan parameter size ke invisible, serta menetapkan ID tombol pengirim formulir login Anda. Contoh:

API modular web

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

API dengan namespace web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

Menggunakan widget reCAPTCHA

Untuk menggunakan widget reCAPTCHA yang terlihat, buat elemen di halaman Anda untuk menampung widget tersebut, lalu buat objek RecaptchaVerifier serta tentukan ID container tersebut. Contoh:

API modular web

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {});

API dengan namespace web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');

Opsional: Menetapkan parameter reCAPTCHA

Anda dapat memilih untuk menetapkan fungsi callback pada objek RecaptchaVerifier yang akan dipanggil ketika pengguna berhasil memecahkan reCAPTCHA atau ketika masa berlaku reCAPTCHA habis sebelum pengguna mengirimkan formulir:

API modular web

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

API dengan namespace web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

Opsional: Merender reCAPTCHA di awal

Jika ingin merender reCAPTCHA di awal sebelum mengirimkan permintaan login, panggil render:

API modular web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

API dengan namespace web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

Setelah render berhasil, Anda akan memperoleh ID widget reCAPTCHA yang dapat digunakan untuk melakukan panggilan ke reCAPTCHA API:

API modular web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

API dengan namespace web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Mengirim kode verifikasi ke ponsel pengguna

Untuk memulai metode login dengan nomor telepon, tampilkan antarmuka yang akan meminta pengguna memasukkan nomor telepon, lalu panggil signInWithPhoneNumber untuk meminta agar Firebase mengirimkan kode autentikasi ke ponsel pengguna melalui SMS:

  1. Dapatkan nomor telepon pengguna.

    Persyaratan hukum dapat berbeda-beda. Namun, sebagai praktik terbaik dan demi menetapkan ekspektasi pengguna, sebaiknya beri tahukan bahwa jika mereka menggunakan metode login melalui telepon, akan muncul pesan SMS berisi permintaan verifikasi dan pemberlakuan tarif standar.

  2. Panggil signInWithPhoneNumber, lalu teruskan ke nomor telepon pengguna dan RecaptchaVerifier yang Anda buat sebelumnya.

    API modular web

    import { getAuth, signInWithPhoneNumber } from "firebase/auth";
    
    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    
    const auth = getAuth();
    signInWithPhoneNumber(auth, phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });

    API dengan namespace web

    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });
    jia signInWithPhoneNumber menghasilkan error, reset reCAPTCHA agar pengguna dapat mencoba lagi:
    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    window.recaptchaVerifier.render().then(function(widgetId) {
      grecaptcha.reset(widgetId);
    });
    

Metode signInWithPhoneNumber menampilkan tantangan reCAPTCHA kepada pengguna. Jika pengguna berhasil memecahkannya, metode ini akan meminta agar Firebase Authentication mengirimkan kode verifikasi ke ponsel pengguna melalui SMS.

Memproses login pengguna dengan kode verifikasi

Setelah panggilan ke signInWithPhoneNumber berhasil, minta pengguna mengetikkan kode verifikasi yang diterima melalui SMS. Kemudian, proses login dengan meneruskan kode tersebut ke metode confirm objek ConfirmationResult yang diteruskan ke pengendali fulfillment signInWithPhoneNumber (yaitu blok then-nya). Contoh:

API modular web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

API dengan namespace web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

Jika panggilan ke confirm berhasil, pengguna berhasil login.

Memperoleh objek AuthCredential menengah

Jika perlu mendapatkan objek AuthCredential untuk akun pengguna, teruskan kode verifikasi dari hasil konfirmasi dan kode verifikasi ke PhoneAuthProvider.credential bukan memanggil confirm:

var credential = firebase.auth.PhoneAuthProvider.credential(confirmationResult.verificationId, code);

Selanjutnya, Anda dapat memproses login pengguna dengan kredensial tersebut:

firebase.auth().signInWithCredential(credential);

Menguji dengan nomor telepon fiktif

Anda dapat menyiapkan nomor telepon fiktif untuk pengembangan melalui Firebase console. Pengujian dengan nomor telepon fiktif memberikan sejumlah manfaat berikut:

  • Menguji autentikasi nomor telepon tanpa menghabiskan kuota penggunaan Anda.
  • Menguji autentikasi nomor telepon tanpa benar-benar mengirim pesan SMS.
  • Menjalankan pengujian berturut-turut dengan nomor telepon yang sama tanpa throttling. Tindakan ini meminimalkan risiko penolakan selama proses peninjauan App store jika peninjau kebetulan menggunakan nomor telepon yang sama untuk melakukan pengujian.
  • Pengujian langsung di lingkungan pengembangan tanpa upaya tambahan, seperti kemampuan untuk melakukan pengembangan dalam simulator iOS atau emulator Android tanpa Layanan Google Play.
  • Menulis pengujian integrasi tanpa diblokir oleh pemeriksaan keamanan yang biasanya diterapkan pada nomor telepon asli di lingkungan produksi.

Nomor telepon fiktif harus memenuhi persyaratan berikut:

  1. Pastikan nomor telepon yang digunakan benar-benar fiktif dan belum pernah ada. Firebase Authentication tidak mengizinkan nomor telepon yang memang ada dan digunakan oleh pengguna sungguhan sebagai nomor telepon pengujian. Salah satu opsinya adalah menggunakan nomor berawalan 555 sebagai nomor telepon pengujian di Amerika Serikat, misalnya: +1 650-555-3434
  2. Nomor telepon harus diformat dengan benar menurut batasan panjang dan batasan lainnya. Nomor telepon tersebut akan melalui validasi yang sama seperti nomor telepon pengguna sungguhan.
  3. Anda dapat menambahkan hingga 10 nomor telepon untuk proses pengembangan.
  4. Gunakan nomor telepon/kode pengujian yang sulit ditebak dan seringlah mengubahnya.

Membuat nomor telepon dan kode verifikasi fiktif

  1. Di Firebase console, buka bagian Authentication.
  2. Di tab Sign-in method, aktifkan penyedia Phone jika Anda belum melakukannya.
  3. Buka menu akordeon Phone numbers for testing.
  4. Berikan nomor telepon yang ingin Anda uji, misalnya: +1 650-555-3434.
  5. Sediakan kode verifikasi 6 digit untuk nomor tersebut, misalnya: 654321.
  6. Klik Add untuk menambahkan nomor telepon. Jika perlu, Anda dapat menghapus nomor telepon beserta kodenya dengan mengarahkan kursor ke baris yang sesuai dan mengklik ikon tempat sampah.

Pengujian manual

Anda dapat langsung mulai menggunakan nomor telepon fiktif dalam aplikasi. Dengan demikian, Anda bisa langsung melakukan pengujian manual selama tahap pengembangan tanpa mengalami masalah kuota atau throttling. Anda juga dapat menguji langsung dari simulator iOS atau emulator Android tanpa menginstal Layanan Google Play.

Ketika Anda memberikan nomor telepon fiktif dan mengirim kode verifikasi, sebenarnya tidak ada SMS yang dikirim. Sebagai gantinya, Anda harus memberikan kode verifikasi yang dikonfigurasi sebelumnya untuk menyelesaikan login.

Saat login selesai, pengguna Firebase dibuat dengan nomor telepon itu. Pengguna tersebut memiliki perilaku dan properti seperti halnya pengguna nomor telepon sungguhan dan dapat mengakses Realtime Database/Cloud Firestore serta layanan lainnya dengan cara yang sama. Token ID yang dibuat selama proses ini memiliki tanda tangan yang sama dengan pengguna nomor telepon sungguhan.

Pilihan lainnya adalah menetapkan peran pengujian melalui klaim khusus pada pengguna ini untuk membedakannya dari pengguna palsu jika Anda ingin membatasi akses lebih lanjut.

Pengujian integrasi

Selain pengujian manual, Firebase Authentication menyediakan API untuk membantu menulis pengujian integrasi untuk pengujian autentikasi ponsel. API ini menonaktifkan verifikasi aplikasi dengan menonaktifkan persyaratan reCAPTCHA di web dan notifikasi push senyap di iOS. Dengan demikian, pengujian otomatisasi dapat dilakukan dalam alur ini dan lebih mudah diimplementasikan. Selain itu, API ini memungkinkan pengujian alur verifikasi instan di Android.

Di web, setel appVerificationDisabledForTesting ke true sebelum merender firebase.auth.RecaptchaVerifier. Tindakan ini akan menyelesaikan reCAPTCHA secara otomatis, sehingga memungkinkan Anda untuk meneruskan nomor telepon tanpa harus menyelesaikannya secara manual. Perlu diperhatikan bahwa penggunaan nomor telepon asli akan tetap menggagalkan proses login meskipun reCAPTCHA dinonaktifkan. Hanya nomor telepon fiktif yang dapat digunakan dengan API ini.

// Turn off phone auth app verification.
firebase.auth().settings.appVerificationDisabledForTesting = true;

var phoneNumber = "+16505554567";
var testVerificationCode = "123456";

// This will render a fake reCAPTCHA as appVerificationDisabledForTesting is true.
// This will resolve after rendering without app verification.
var appVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
// signInWithPhoneNumber will call appVerifier.verify() which will resolve with a fake
// reCAPTCHA response.
firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
    .then(function (confirmationResult) {
      // confirmationResult can resolve with the fictional testVerificationCode above.
      return confirmationResult.confirm(testVerificationCode)
    }).catch(function (error) {
      // Error; SMS not sent
      // ...
    });

Pemverifikasi aplikasi reCAPTCHA fiktif yang terlihat dan tidak terlihat berperilaku berbeda ketika verifikasi aplikasi dinonaktifkan:

  • reCAPTCHA Terlihat: Ketika dirender melalui appVerifier.render(), reCAPTCHA terlihat akan otomatis selesai dengan sendirinya setelah penundaan sepersekian detik. Hal ini sama seperti pengguna langsung mengklik reCAPTCHA setelah rendering. Masa berlaku respons reCAPTCHA akan berakhir setelah beberapa waktu, kemudian reCAPTCHA akan diselesaikan secara otomatis lagi.
  • reCAPTCHA Tidak Terlihat: reCAPTCHA tidak terlihat tidak melakukan penyelesaian otomatis pada proses rendering, tetapi melakukannya saat pemanggilan appVerifier.verify() atau ketika anchor tombol reCAPTCHA diklik setelah penundaan sepersekian detik. Demikian pula, masa berlaku respons akan berakhir setelah beberapa waktu dan reCAPTCHA hanya akan melakukan penyelesaian otomatis setelah pemanggilan appVerifier.verify() atau saat anchor tombol reCAPTCHA diklik lagi.

Setiap kali reCAPTCHA fiktif terselesaikan, fungsi callback yang sesuai dipicu seperti yang diharapkan dengan respons palsu. Jika ditentukan, callback akhir masa berlaku akan terpicu pada akhir masa berlaku.

Langkah berikutnya

Setelah pengguna login untuk pertama kalinya, akun pengguna baru akan dibuat dan ditautkan ke kredensial, yaitu nama pengguna dan sandi, nomor telepon, atau informasi penyedia autentikasi, yang digunakan pengguna tersebut untuk login. Akun baru ini disimpan sebagai bagian dari project Firebase Anda, dan dapat digunakan untuk mengidentifikasi pengguna di setiap aplikasi dalam project, terlepas dari cara pengguna login.

  • Di aplikasi Anda, cara yang direkomendasikan untuk mengetahui status autentikasi pengguna adalah dengan menetapkan observer pada objek Auth. Selanjutnya, 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 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:

API modular web

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

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

API dengan namespace web

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