Belajar 2FA Authentication - Konsep Dasar: TOTP & Arsitektur Utama
Episode 2 of 23

Belajar 2FA Authentication - Konsep Dasar: TOTP & Arsitektur Utama

Episode ini membedah anatomi kode TOTP: shared secret Base32, counter waktu epoch dibagi 30 detik, HMAC-SHA1, dan truncation menjadi 6 digit. Kalian juga mempelajari arsitektur end-to-end dari generate secret, QR code, verifikasi pertama, sampai login dua langkah, termasuk pentingnya sinkronisasi jam.

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

Pendahuluan

Sebelum menulis kode, kalian harus memahami apa yang sebenarnya terjadi di balik 6 digit yang berubah setiap 30 detik. Episode 2 membedah TOTP dari dalam: shared secret, counter waktu, HMAC-SHA1, truncation, dan sinkronisasi jam. Pemahaman ini membedakan kalian dari developer yang sekadar menyalin pustaka.

Setelah memahami anatomi kode, kita akan menelusuri arsitektur utama fitur 2FA end-to-end — dari server membuat secret, merender QR code, sampai verifikasi login dua langkah. Kalian juga akan melihat langsung kode TOTP yang dihitung dengan otplib, dan mengapa jam yang akurat adalah syarat mutlak TOTP.

Anatomi Kode TOTP

Shared Secret dalam Base32

TOTP dimulai dari shared secret — nilai acak yang hanya diketahui server dan perangkat pengguna. Secret ini dikodekan dalam Base32 (RFC 3548), sehingga hanya memakai huruf A-Z dan angka 2-7. Bentuk Base32 inilah yang tampak di Google Authenticator saat kalian memasukkan secret secara manual, misalnya JBSWY3DPEHPK3PXP.

Base32 membuat secret mudah diketik manusia tanpa karakter yang mudah tertukar, dan bisa di-encode ke dalam URI otpauth://. Secret harus unik per pengguna dan jangan pernah dipakai ulang antar akun — episode 4 akan membahas pembuatannya secara detail.

Counter Waktu: Epoch dibagi 30 Detik

TOTP adalah HOTP dengan counter yang berasal dari waktu. Counter dihitung sebagai hasil bagi pembulatan ke bawah epoch UNIX (detik sejak 1 Januari 1970) dengan periode. Dengan periode 30 detik, nilai counter berganti setiap 30 detik — inilah yang membuat kode tampak berdetak.

Perhitungan sederhananya:

Rumus counter TOTP
counter = floor(epoch_seconds / 30)

Karena server dan client memakai waktu nyata, keduanya menghasilkan counter yang sama pada jendela waktu yang sama. Di sinilah sinkronisasi jam menjadi krusial — TOTP gagal total jika salah satu sisi telat puluhan detik.

HMAC-SHA1, Truncation, dan 6 Digit

Kode TOTP dihitung dengan fungsi HMAC-SHA1 yang menerima secret (setelah dekode Base32) dan counter sebagai pesan. Hasilnya adalah 20 byte, lalu dynamic truncation mengambil 4 byte dari posisi yang ditentukan oleh 4 bit terakhir hash, memotong 31 bit, dan mengambil modulus 1.000.000. Hasil akhirnya adalah 6 digit — dijamin kode selalu berbentuk angka 6 digit seperti 123456.

Rantai lengkapnya: secret ditambah waktu, lalu HMAC-SHA1, truncate, modulo 1.000.000, dan hasilnya 6 digit.

Variasi: HMAC-SHA256 dan Periode Lain

RFC 6238 tidak membatasi TOTP pada HMAC-SHA1. Parameter algorithm bisa diganti menjadi SHA256 atau SHA512, dan period bisa diubah dari 30 detik default. otplib membaca parameter dari URI provisioning sehingga kode selalu cocok dengan apa yang dikonfigurasi aplikasi authenticator.

Kompatibilitas terbaik tetap di HMAC-SHA1 dengan 6 digit dan periode 30 detik — semua aplikasi mendukung kombinasi ini. Anggap variasi algoritma sebagai fitur lanjutan untuk kebutuhan khusus, bukan pilihan default.

Menghitung TOTP dengan otplib

Implementasi di atas sudah diuji ribuan kali di dalam otplib. Kalian cukup memakai API authenticator:

Generate kode TOTP saat ini
node -e "
const { authenticator } = require('otplib');
const secret = 'JBSWY3DPEHPK3PXP';
const token = authenticator.generate(secret);
console.log('TOTP saat ini:', token);
console.log('Counter step:', Math.floor(Date.now() / 1000 / 30));
"

Jalankan perintah itu dua kali dalam jarak 30 detik untuk melihat kode berubah. Metode authenticator.generate menerima secret Base32 dan mengembalikan 6 digit — persis yang dihasilkan Google Authenticator untuk secret yang sama. Episode 4 dan 6 akan memakai API ini untuk enrollment dan verifikasi.

Tip

otplib menerima opsi global melalui authenticator.options = { step: 30, window: 1 }. Parameter algorithm, digits, dan period pada URI provisioning juga dibaca otomatis oleh authenticator.generate, sehingga hasilnya selalu konsisten dengan aplikasi authenticator.

Arsitektur 2FA End-to-End

Alur Enrollment

Seluruh series dibangun di atas satu arsitektur utama. Urutannya:

  1. Server membuat secret unik per pengguna dan menampilkan URI provisioning.
  2. Frontend merender URI menjadi QR code di halaman Enable 2FA.
  3. Pengguna memindai QR dengan Google Authenticator — secret tersimpan di aplikasi.
  4. Pengguna memasukkan kode pertama, server memverifikasi sebelum mengaktifkan 2FA.
  5. Secret disimpan terenkripsi di database, dan recovery codes ditampilkan sekali.

Episode 4 sampai 7 membedah setiap langkah ini satu per satu.

Login Dua Langkah

Setelah enrollment, login berubah menjadi dua langkah:

  1. Langkah pertama: verifikasi password. Server belum memberi session penuh, hanya menandai status pendingMfa.
  2. Langkah kedua: verifikasi 6 digit TOTP. Server baru mengeluarkan session penuh setelah kode valid.

Arsitektur ini mencegah pengguna mengakses protected route sebelum menyelesaikan tantangan 2FA. Implementasinya akan dibahas penuh di episode 8.

Sinkronisasi Jam dan Clock Skew

TOTP sangat peka terhadap waktu. Standar RFC 6238 menyarankan server mengizinkan toleransi satu step di setiap sisi — total jendela tiga step — untuk mengakomodasi selisih jam perangkat. Di server produksi, gunakan NTP dan jangan andalkan waktu server yang mengambang:

Aktifkan sinkronisasi waktu NTP
sudo timedatectl set-ntp true
timedatectl status

Output timedatectl status menampilkan baris "System clock synchronized: yes" ketika NTP aktif. Episode 6 akan memakai toleransi step ini saat verifikasi pertama, dan episode 16 mengujinya dengan clock skew buatan.

Penutup

Episode 2 membedah inti TOTP: secret Base32 sebagai rahasia bersama, counter dari epoch dibagi 30 detik, HMAC-SHA1 dengan dynamic truncation menjadi 6 digit, dan arsitektur enrollment serta login dua langkah yang menopang seluruh series.

Inti yang harus dibawa pulang:

  • TOTP memakai shared secret Base32 yang unik per pengguna.
  • Counter TOTP adalah epoch UNIX dibagi 30 detik.
  • Kode dihitung dengan HMAC-SHA1, truncation, lalu modulo 1.000.000.
  • otplib mengabstraksi semuanya lewat API authenticator.
  • Arsitektur 2FA terdiri dari enrollment, simpan secret, dan login dua langkah.
  • Sinkronisasi jam lewat NTP adalah syarat mutlak TOTP.

Di episode 3 selanjutnya kita akan membangun fondasi autentikasi: login dan session — registrasi password dengan bcrypt, cookie HttpOnly dan JWT, struktur user model yang akan menyimpan secret 2FA, serta endpoint auth yang nanti disisipi tantangan MFA.