We are passionate about transforming your ideas into impactful, secure, and innovative technology solutions.

Social

Web Development

Tutorial: Login Tanpa Kata Sandi dengan Passkey (WebAuthn/FIDO2) untuk Aplikasi Web

Kebocoran kredensial dan infostealer terus menghantui bisnis Indonesia sepanjang 2026, dan akarnya selalu sama: kata sandi. Artikel ini mengupas cara kerja passkey berbasis WebAuthn dan FIDO2, lalu memandu Anda langkah demi langkah menambahkan login tanpa kata sandi yang tahan phishing ke aplikasi web menggunakan SimpleWebAuthn.

By Siberindo··7 min read

Sepanjang 2026, kabar kebocoran kredensial di Indonesia nyaris tak pernah surut. Log dari infostealer yang berisi jutaan pasangan email dan kata sandi diperjualbelikan di forum bawah tanah, lalu dipakai untuk mengambil alih akun email bisnis, dashboard admin, hingga panel hosting. Akar masalahnya selalu sama: kata sandi. Selama sistem Anda masih bergantung pada sesuatu yang bisa diketik, ditebak, di-phishing, atau dicuri dari sebuah basis data, selama itu pula pintu belakang tetap terbuka. Kabar baiknya, ada standar yang secara arsitektur menutup celah tersebut, dan kini sudah matang untuk produksi: passkey. Artikel ini menjelaskan cara kerjanya sekaligus memandu Anda menambahkan login tanpa kata sandi ke aplikasi web menggunakan WebAuthn.

Mengapa Kata Sandi Sudah Tidak Memadai

Kata sandi memiliki kelemahan bawaan yang tidak bisa ditambal oleh kebijakan sepanjang apa pun. Ia adalah shared secret: rahasia yang sama diketahui oleh pengguna dan disimpan (dalam bentuk hash) di server Anda. Ketika server bocor, penyerang mendapatkan bahan untuk serangan offline cracking. Ketika pengguna tertipu halaman palsu, mereka menyerahkan rahasia itu secara sukarela. Multi-Factor Authentication (MFA) berbasis OTP dan aplikasi authenticator memang menaikkan palang secara signifikan, tetapi kode OTP pun masih bisa di-relay oleh kit phishing modern dan serangan adversary-in-the-middle.

Inilah alasan otoritas keamanan mulai membedakan MFA biasa dari MFA yang tahan phishing (phishing-resistant MFA). CISA di Amerika Serikat secara eksplisit menempatkan FIDO dan WebAuthn dalam kategori tahan phishing, sementara NIST melalui SP 800-63B mengklasifikasikan implementasi FIDO2 yang terikat perangkat keras pada tingkat jaminan tertinggi (AAL3). Bagi organisasi Indonesia yang tunduk pada UU No. 27 Tahun 2022 tentang Pelindungan Data Pribadi, memilih mekanisme autentikasi sekuat ini adalah wujud nyata dari kewajiban menerapkan langkah teknis yang memadai untuk mengamankan data pribadi.

Apa Itu Passkey, WebAuthn, dan FIDO2

Tiga istilah ini sering tertukar, padahal saling melengkapi. FIDO2 adalah payung standar dari FIDO Alliance. WebAuthn adalah API standar W3C yang tersedia di browser dan menjadi antarmuka bagi aplikasi web untuk memakai FIDO2. Sedangkan passkey adalah nama ramah pengguna untuk kredensial FIDO2 yang bisa disinkronkan antarperangkat lewat pengelola seperti iCloud Keychain, Google Password Manager, atau Microsoft Entra ID.

Inti keamanannya terletak pada kriptografi kunci publik. Saat pengguna mendaftarkan passkey, perangkatnya membuat sepasang kunci: kunci privat yang tidak pernah meninggalkan perangkat (idealnya tersimpan di dalam secure enclave atau TPM) dan kunci publik yang dikirim ke server Anda. Server hanya menyimpan kunci publik. Karena kunci publik tidak berguna bagi penyerang, kebocoran basis data tidak lagi mengekspos apa pun yang bisa dipakai untuk masuk. Tidak ada rahasia yang bisa dicuri, tidak ada yang bisa digunakan ulang, dan tidak ada yang bisa di-phishing.

Kunci passkey terikat pada origin (domain) situs asli. Browser menolak menandatangani tantangan untuk domain yang tidak cocok, sehingga halaman phishing di domain mirip pun tidak akan pernah bisa memicu passkey yang sah.

Dua Upacara WebAuthn: Registrasi dan Autentikasi

Seluruh mekanisme WebAuthn dibangun dari dua alur yang disebut ceremony. Registrasi adalah proses membuat passkey baru untuk sebuah akun. Autentikasi adalah proses memakai passkey yang sudah ada untuk login. Keduanya berbentuk perjalanan bolak-balik dua langkah: server menerbitkan challenge acak beserta opsi, browser memicu WebAuthn API untuk meminta persetujuan pengguna (sidik jari, Face ID, PIN, atau kunci perangkat keras), lalu mengembalikan respons yang ditandatangani, dan server memverifikasi respons itu sebelum memercayainya.

Membangun verifikasi ini dari nol berisiko tinggi karena melibatkan penguraian CBOR, verifikasi attestation, dan manajemen challenge yang rawan bug halus. Karena itu kita memakai pustaka teruji. Pada tutorial ini kita menggunakan SimpleWebAuthn, pustaka TypeScript yang paling banyak dipakai untuk keperluan ini.

Tutorial: Menambahkan Passkey ke Aplikasi Web

Berikut langkah-langkah membangun login passkey pada aplikasi Node.js. Contoh sengaja diringkas agar fokus pada alur inti; sesuaikan penyimpanan dan penanganan sesi dengan kerangka kerja Anda.

Langkah 1: Pasang pustaka

npm install @simplewebauthn/server @simplewebauthn/browser

Paket server berjalan di backend untuk membuat opsi dan memverifikasi respons, sedangkan paket browser membungkus panggilan WebAuthn native di sisi klien beserta encoding base64url yang dibutuhkannya.

Langkah 2: Tentukan parameter Relying Party

Relying Party (RP) adalah istilah WebAuthn untuk aplikasi Anda. Tiga nilai ini harus konsisten di seluruh kode:

const rpName = "Portal Siberindo";
const rpID = "app.siberindo.io";        // domain, tanpa skema/port
const origin = "https://app.siberindo.io"; // origin lengkap

Nilai rpID wajib cocok dengan domain yang diakses pengguna. Ketidakcocokan di sini adalah penyebab kegagalan paling umum saat pertama kali mengintegrasikan passkey.

Langkah 3: Buat opsi registrasi

import { generateRegistrationOptions } from "@simplewebauthn/server";

app.post("/register/start", async (req, res) => {
  const user = req.user; // pengguna yang sudah login/terverifikasi

  const options = await generateRegistrationOptions({
    rpName,
    rpID,
    userName: user.email,
    attestationType: "none",
    authenticatorSelection: {
      residentKey: "preferred",
      userVerification: "preferred",
    },
  });

  // Simpan challenge di sesi untuk diverifikasi nanti
  req.session.challenge = options.challenge;
  res.json(options);
});

Perhatikan bahwa challenge disimpan sementara di sesi. Nilai acak ini mencegah serangan replay: respons hanya sah bila menandatangani challenge yang tepat kita terbitkan.

Langkah 4: Panggil WebAuthn di browser

import { startRegistration } from "@simplewebauthn/browser";

async function daftarPasskey() {
  const optionsRes = await fetch("/register/start", { method: "POST" });
  const options = await optionsRes.json();

  // Memicu prompt biometrik/PIN lewat navigator.credentials.create()
  const attResp = await startRegistration({ optionsJSON: options });

  await fetch("/register/finish", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(attResp),
  });
}

Langkah 5: Verifikasi dan simpan kunci publik

import { verifyRegistrationResponse } from "@simplewebauthn/server";

app.post("/register/finish", async (req, res) => {
  const verification = await verifyRegistrationResponse({
    response: req.body,
    expectedChallenge: req.session.challenge,
    expectedOrigin: origin,
    expectedRPID: rpID,
  });

  if (verification.verified) {
    const info = verification.registrationInfo;
    // Simpan credentialID, kunci publik, dan counter ke basis data
    await db.savePasskey(req.user.id, info.credential);
  }
  res.json({ verified: verification.verified });
});

Server hanya menyimpan credentialID, kunci publik, dan sebuah counter. Tidak ada kata sandi, tidak ada rahasia yang bisa dieksfiltrasi.

Langkah 6: Alur login

Autentikasi mengikuti pola cermin. Server memanggil generateAuthenticationOptions untuk menerbitkan challenge baru, browser memanggil startAuthentication, lalu server memverifikasinya:

import { verifyAuthenticationResponse } from "@simplewebauthn/server";

app.post("/login/finish", async (req, res) => {
  const passkey = await db.getPasskeyById(req.body.id);

  const verification = await verifyAuthenticationResponse({
    response: req.body,
    expectedChallenge: req.session.challenge,
    expectedOrigin: origin,
    expectedRPID: rpID,
    credential: passkey,
  });

  if (verification.verified) {
    // Perbarui counter, lalu buat sesi login
    await db.updateCounter(passkey.id, verification.authenticationInfo.newCounter);
    req.session.userId = passkey.userId;
  }
  res.json({ verified: verification.verified });
});

Nilai counter yang selalu bertambah membantu mendeteksi kloning kredensial: jika counter yang masuk lebih kecil dari yang tersimpan, ada indikasi anomali yang patut diblokir.

Praktik Terbaik dan Catatan Kepatuhan

Beberapa hal yang perlu diperhatikan saat menerapkan passkey di lingkungan produksi:

  • Sediakan mekanisme pemulihan. Pengguna bisa kehilangan perangkat. Dukung pendaftaran lebih dari satu passkey per akun dan siapkan jalur pemulihan yang tetap aman, misalnya kode cadangan atau verifikasi berlapis lewat kanal terpisah.
  • Terapkan secara bertahap. Anda tidak harus menghapus kata sandi dalam semalam. Mulailah dengan menawarkan passkey sebagai opsi, ukur adopsi, lalu jadikan wajib untuk akun berisiko tinggi seperti administrator.
  • Gunakan kunci perangkat keras untuk peran kritis. Untuk akses ke sistem paling sensitif, kunci FIDO2 fisik yang tidak dapat disinkronkan memberikan tingkat jaminan AAL3 sesuai NIST SP 800-63B.
  • Catat setiap peristiwa autentikasi. Simpan log registrasi dan login sebagai jejak audit. Ini penting untuk investigasi forensik sekaligus mendukung prinsip akuntabilitas dalam UU PDP.

Dari sisi hukum, memilih autentikasi tahan phishing memperkuat posisi kepatuhan organisasi. UU PDP mewajibkan pengendali data menerapkan langkah teknis dan organisasi yang proporsional terhadap risiko. Mengganti kata sandi dengan passkey secara langsung mengurangi permukaan serangan pengambilalihan akun, yang selama ini menjadi salah satu penyebab utama insiden kebocoran data pribadi.

Penutup

Passkey bukan lagi teknologi eksperimental. Dengan dukungan penuh dari Apple, Google, dan Microsoft, serta pengakuan dari NIST dan CISA sebagai autentikasi tahan phishing, 2026 adalah momen yang tepat bagi organisasi Indonesia untuk mulai beralih. Secara teknis, integrasinya kini jauh lebih sederhana berkat pustaka seperti SimpleWebAuthn yang menyembunyikan kerumitan kriptografi di balik beberapa panggilan fungsi. Dengan menyingkirkan shared secret yang menjadi bahan bakar ekonomi kredensial curian, Anda tidak sekadar menaikkan kenyamanan login, melainkan menutup salah satu celah paling produktif yang dieksploitasi penyerang. Mulailah dengan satu alur, uji secara menyeluruh, dan bangun jalur menuju masa depan tanpa kata sandi.

Share