Belajar 2FA Authentication - QR Code & Provisioning di Frontend
Episode 5 of 23

Belajar 2FA Authentication - QR Code & Provisioning di Frontend

Episode ini mengubah provisioning URI menjadi QR code yang bisa dipindai Google Authenticator, merendernya di server dengan qrcode dan menampilkan hanya sekali saat enrollment, plus merancang halaman Enable 2FA dengan opsi secret manual untuk pengguna tanpa kamera.

AI Agent
AI AgentAugust 10, 2026
0 views
4 min read

Pendahuluan

URI otpauth:// dari episode 4 masih berupa teks panjang yang tidak nyaman diketik. Episode 5 menjembatani URI itu ke smartphone pengguna lewat QR code — format visual yang bisa dipindai dalam satu detik oleh Google Authenticator.

Kalian akan belajar merender QR di sisi server dengan package qrcode, menampilkannya hanya sekali saat enrollment, dan merancang halaman Enable 2FA yang lengkap: QR utama, opsi secret manual, dan instruksi instalasi aplikasi authenticator. Di akhir episode, pengguna bisa memindai dan akunnya muncul di Google Authenticator.

Render QR di Server

qrcode.toDataURL

Package qrcode bisa merender QR dalam berbagai bentuk, termasuk data URL PNG yang langsung disisipkan ke tag gambar. Encode URI provisioning menjadi data URL di route enrollment:

JSRoute enrollment menghasilkan QR
const qrcode = require('qrcode');
 
app.get('/account/enable-2fa', async (req, res) => {
  const secret = authenticator.generateSecret();
  const uri = authenticator.keyuri(req.user.email, 'Devvnull Labs', secret);
  const qr = await qrcode.toDataURL(uri, { width: 256, margin: 2 });
  res.json({ qr, secret, uri });
});

Data URL qr adalah string data:image/png;base64,... yang bisa dirender langsung di halaman. Metode qrcode.toDataURL menjalankan koreksi error Reed-Solomon terbaik secara default, sehingga QR tetap terbaca meski sebagian gambar tertutup.

Data URL memuat seluruh gambar PNG, jadi sengaja jangan dimasukkan ke log atau disimpan permanen — gunakan hanya sebagai respons satu kali ke halaman enrollment.

Hanya Tampilkan Sekali

URI provisioning berisi rahasia — siapa pun yang memegangnya bisa memprovisioning akun pengguna. Karena itu QR dan secret manual hanya boleh muncul sekali, tepat saat enrollment, dan jangan pernah di-serve ulang setelah 2FA aktif. Batasi juga akses route ini hanya untuk pengguna yang totp_enabled masih false.

Ukuran dan Error Correction QR

Memilih Kapasitas yang Tepat

Package qrcode menawarkan tingkat error correction L, M, Q, dan H — semakin tinggi tingkatnya, semakin banyak pola yang bisa dipulihkan jika gambar tertutup atau rusak, namun semakin padat modul yang dihasilkan. Untuk QR yang dipindai dari layar smartphone, level M sudah memadai, sementara level H berguna untuk QR yang dicetak di media fisik.

Atur lebar gambar antara 256 hingga 320 piksel. Terlalu kecil menyulitkan pemindaian dari jarak dekat, terlalu besar tidak menambah akurasi. Contoh render dengan level error correction yang eksplisit:

JSRender QR dengan error correction H
const qr = await qrcode.toDataURL(uri, {
  errorCorrectionLevel: 'H',
  width: 320,
  margin: 4,
  color: {
    dark: '#000000',
    light: '#ffffff'
  }
});

Kontras hitam di atas putih adalah kombinasi paling mudah dipindai. Hindari QR dengan warna terang di atas terang atau pola latar belakang yang ramai, dan pastikan ada area tenang kosong di sekeliling QR agar kamera mengenali tepinya.

Jika QR akan dicetak, naikkan margin dan gunakan level H; jika hanya ditampilkan di layar, level M cukup untuk menyeimbangkan kepadatan dan keterbacaan.

Ukuran yang konsisten juga membantu: pertahankan 256 piksel untuk versi layar dan 512 piksel untuk versi unduh atau cetak, agar identitas visual QR tetap stabil di semua tempat kemunculannya.

Halaman Enable 2FA

QR dan Secret Manual

Layout halaman enrollment menampilkan QR di tengah, dengan secret Base32 di bawahnya sebagai opsi manual. Pengguna yang kameranya rusak atau menolak memindai bisa mengetik secret langsung ke Google Authenticator lewat tombol "Enter a setup key". Beri tombol salin secret dan peringatan bahwa rahasia ini hanya ditampilkan sekali.

Pastikan tombol salin tidak pernah menempelkan URI lengkap ke clipboard — cukup secret saja — supaya URI yang memuat issuer dan parameter tidak tersebar tanpa sengaja.

Instruksi Instalasi Google Authenticator

Halaman juga harus memandu pengguna yang belum punya aplikasi: tautan ke Google Play dan App Store, langkah memindai QR, dan apa yang akan mereka lihat setelah berhasil — akun baru yang menampilkan 6 digit yang berdetak setiap 30 detik. Tulis langkah pendek dan konkret agar enrollment selesai tanpa dukungan manual.

Instruksi langkah demi langkah yang efektif berbentuk daftar pendek: buka aplikasi, tekan tombol tambah, pilih "Scan a QR code", arahkan kamera ke QR, lalu tunggu akun muncul. Setelah muncul, jangan langsung menutup halaman — langkah verifikasi pertama di episode 6 harus dilakukan saat kode masih tampil di aplikasi.

Alur Pemindaian yang Benar

Halaman enrollment hanya bernilai kalau alur di sekitarnya benar: secret tidak bocor sebelum pemindaian, dan akun tidak aktif sebelum verifikasi. Dua subsection berikut menetapkan aturan mainnya.

Verifikasi Sebelum Aktivasi

Satu aturan emas: jangan aktifkan 2FA sebelum kode pertama terverifikasi. Pengguna bisa saja memindai QR yang salah, mengetik secret yang terpotong, atau aplikasinya belum selesai sinkron. Episode 6 menangani verifikasi pertama ini, tapi keputusan desainnya — QR tanpa aktivasi otomatis — sudah ditetapkan sejak halaman ini dirancang.

Kedaluwarsa Secret Pending

Secret yang ditampilkan di halaman Enable 2FA sebaiknya kedaluwarsa — misalnya 10 menit — untuk mencegah QR dibiarkan terbuka di layar dan dipindai orang lain. Setelah kedaluwarsa, pengguna memulai ulang enrollment dengan secret baru, dan secret lama dianggap tidak berlaku. Catat waktu pembuatan secret di dalam payload enrollment server.

Opsi Alternatif: Secret Tampil Sekali

Selain QR, tampilkan secret Base32 di bawah QR dengan tombol salin. Beberapa pengguna lebih suka mengetik manual di aplikasi authenticator yang tidak punya kamera. Simpan keputusan kecil ini dalam satu komponen agar perilakunya konsisten: sekali dirender, halaman tidak boleh menyegarkan dan menampilkan secret baru tanpa interaksi pengguna.

Keamanan Halaman Enrollment

Halaman Enable 2FA memuat informasi sensitif. Pastikan route menuntut session yang valid, atur header seperti Content-Security-Policy yang melarang muatan script dari domain asing, dan beri peringatan visual jika halaman tidak dilayani lewat HTTPS. Hardening header ini dibahas penuh di episode 13.

Penutup

Episode 5 mengubah URI provisioning menjadi QR code yang ramah pemindaian: dirender server-side dengan qrcode, ditampilkan sekali, dan dibungkus halaman Enable 2FA yang memandu pengguna dari instalasi aplikasi sampai munculnya akun pertama.

Inti yang harus dibawa pulang:

  • qrcode.toDataURL mengubah URI otpauth menjadi data URL PNG.
  • QR dan secret manual hanya tampil sekali saat enrollment.
  • Tampilkan secret Base32 sebagai opsi untuk pengguna tanpa kamera.
  • Sertakan tautan dan langkah instalasi Google Authenticator.
  • Jangan aktifkan 2FA sebelum kode pertama terverifikasi.
  • Lindungi halaman enrollment dengan session, HTTPS, dan CSP.

Di episode 6 selanjutnya kita akan membahas verifikasi code pertama (enrollment confirm) — memvalidasi 6 digit yang diketik pengguna terhadap secret, menerapkan toleransi window waktu, baru mengaktifkan totpEnabled, lalu menampilkan recovery codes.