API yang kita bangun pada Section REST API menerima permintaan dari siapa pun yang mengetahui alamat servernya. Endpoint DELETE /tugas/1 akan menghapus data hanya bermodal URL — padahal tugas itu milik seseorang tertentu. Sebelum menambahkan mekanisme keamanan, kita perlu memisahkan dua pertanyaan yang sering dicampuradukkan: siapa pengirim permintaan, dan apa yang boleh dilakukan pengirim itu. Chapter ini membahas kerangka berpikirnya; chapter-chapter berikutnya mewujudkannya dalam kode Node.js mulai dari penyimpanan sandi hingga kontrol akses berbasis peran.

Authentication Menjawab Siapa #

Authentication adalah proses memverifikasi identitas pengirim permintaan. Ketika Budi mengirim email dan sandi ke endpoint login, server memeriksa apakah pasangan itu cocok dengan rekaman yang dimiliki; bila cocok, server tahu permintaan selanjutnya dari Budi memang datang dari Budi. Authorization baru berjalan setelah identitas diketahui: server menentukan apakah Budi boleh menghapus tugas nomor 1 — misalnya karena tugas itu milik Budi, atau karena peran Budi adalah admin.

Urutan ini penting. Authorization tanpa authentication tidak bermakna — “boleh menghapus” selalu terikat pada identitas tertentu, bukan pada permintaan anonim. Sebaliknya, authentication tanpa authorization hanya memberi tahu siapa pengirimnya tanpa membatasi apa pun yang bisa dilakukan.

AspekAuthenticationAuthorization
Pertanyaan yang dijawabSiapa pengirim permintaan ini?Apa yang boleh dilakukan pengguna itu?
Urutan berjalanSelalu lebih duluSetelah identitas diketahui
Status saat gagal401 (belum atau gagal masuk)403 (identitas diketahui, izin kurang)
Contoh mekanismesandi + hash, session, tokendaftar izin, peran, kepemilikan data

Tiga Kelompok Faktor Autentikasi #

Cara membuktikan identitas (faktor) terbagi tiga kelompok besar. Menggabungkan dua faktor dari kelompok berbeda menghasilkan multi-factor authentication (MFA) — inilah alasan kebocoran satu faktor belum tentu membuat akun bisa dimasuki pihak lain.

KelompokDasar pembuktianContoh
Knowledge (pengetahuan)Sesuatu yang hanya diketahui pemiliknyasandi, PIN, jawaban pertanyaan pemulihan
Possession (kepemilikan)Sesuatu yang hanya dimiliki pemiliknyaponsel untuk kode OTP, kunci keamanan fisik, file kunci
Inherent (melekat)Karakteristik tubuh pemiliknyasidik jari, wajah, pola retina

Aplikasi web Node.js paling sering memakai faktor knowledge (sandi) sebagai pintu masuk pertama, lalu menambahkan faktor possession lewat kode OTP atau kunci keamanan untuk akun yang lebih sensitif.

Di Mana Status Login Disimpan #

HTTP bersifat tanpa status: setiap permintaan berdiri sendiri dan server tidak mengingat permintaan sebelumnya. Agar Budi tidak perlu mengirim sandi pada setiap permintaan, hasil login harus diwakili sesuatu yang menyertai permintaan berikutnya. Ada dua keluarga solusi, dan seluruh chapter pada Section ini berdiri di atas pilihan di antara keduanya.

AspekSession (stateful)Token seperti JWT (stateless)
Lokasi data loginDi server (Map, database, Redis)Tertera di dalam token yang disimpan klien
Yang dikirim klienCookie berisi id sesiToken pada header Authorization
Cara server memverifikasiMencari id sesi di penyimpananMenghitung ulang tanda tangan token
Mencabut akses segeraMudah: hapus sesi dari penyimpananSulit: token tetap valid sampai kedaluwarsa
Beban saat membesarPenyimpanan harus dibagi antar serverServer tidak butuh penyimpanan bersama

Tidak ada pemenang mutlak. Aplikasi monolit biasanya nyaman dengan session; API publik yang dilayani banyak server lebih sering memilih token. Kita akan membangun keduanya dari nol agar keputusan kelak diambil berdasarkan pengalaman, bukan tren.

Alur Lengkap dalam Satu Diagram #

Bagan berikut merangkai kedua gerbang tersebut dalam satu alur permintaan yang khas:

Titik kritisnya ada dua: pertukaran kredensial dengan bukti login di awal, lalu pemeriksaan bukti itu pada setiap permintaan berikutnya. Format bukti inilah yang membedakan session (Chapter Session dan Cookie) dari token (Chapter Token dan JWT).

Kedua Gerbang dalam Bentuk Kode #

Sebelum menyentuh HTTP, mari kita lihat kedua pertanyaan itu bekerja dalam satu berkas sederhana. Program berikut memisahkan data profil dari data kredensial, lalu menyediakan dua function sesuai dua gerbang kita.

js
// Basis data contoh: profil pengguna dan kredensial dipisah.
const profil = new Map([
  ['[email protected]', { nama: 'Budi', peran: 'editor' }],
  ['[email protected]', { nama: 'Siti', peran: 'admin' }],
]);
const kredensial = new Map([
  ['[email protected]', 'sandi-budi-2026'],
  ['[email protected]', 'sandi-siti-2026'],
]);

// Pertanyaan pertama - authentication: siapa pengirim permintaan ini?
function autentikasi(email, sandi) {
  const sandiTersimpan = kredensial.get(email);
  if (sandiTersimpan === undefined || sandiTersimpan !== sandi) return null;
  return profil.get(email);
}

// Pertanyaan kedua - authorization: apa yang boleh dilakukan pengguna itu?
function boleh(user, aksi) {
  const izin = {
    baca: ['editor', 'admin'],
    tulis: ['editor', 'admin'],
    hapus: ['admin'],
  };
  return izin[aksi].includes(user.peran);
}

const budi = autentikasi('[email protected]', 'sandi-budi-2026');
console.log('Login Budi        :', budi.nama, `(${budi.peran})`);
console.log('Login sandi salah :', autentikasi('[email protected]', 'sandi-salah'));
console.log('Budi baca tugas   :', boleh(budi, 'baca'));
console.log('Budi hapus tugas  :', boleh(budi, 'hapus'));
const siti = autentikasi('[email protected]', 'sandi-siti-2026');
console.log('Siti hapus tugas  :', boleh(siti, 'hapus'));

Output yang Dihasilkan:

text
Login Budi        : Budi (editor)
Login sandi salah : null
Budi baca tugas   : true
Budi hapus tugas  : false
Siti hapus tugas  : true

Mari kita telaah bagian-bagian pentingnya:

  1. Baris 2-9 (dua Map terpisah): profil dan kredensial disimpan terpisah sejak awal — kebiasaan yang memudahkan saat kredensial nantinya dipindah ke tabel khusus dengan hash.
  2. Baris 12-16 (function autentikasi): menerima email dan sandi, mengembalikan null bila sandi tidak cocok, atau object profil bila cocok. Nilai balik null inilah bentuk paling sederhana dari kegagalan authentication.
  3. Baris 19-26 (function boleh): menerima pengguna yang sudah terautentikasi dan nama aksi, lalu memeriksa daftar izin. Perhatikan bahwa function ini tidak pernah melihat sandi — identitas sudah jadi masukan.
  4. Baris 28-34: Budi berhasil masuk namun ditolak untuk aksi hapus, sementara Siti lolos karena perannya admin. Dua pengguna, dua hasil authorization berbeda, meski keduanya lulus authentication.

Kerangka dua gerbang ini akan menemani seluruh Section. Langkah pertama mewujudkannya menanti di depan: sandi pengguna tidak boleh disimpan dalam bentuk aslinya, sehingga Chapter Password Hashing dengan scrypt mulai dari alasan mengapa hash bukan enkripsi.

Referensi lanjutan: ringkasan HTTP authentication pada MDN memetakan istilah realm dan skema seperti Basic serta Bearer yang akan kita pakai pada chapter-chapter berikutnya.