Episode ini menambahkan lapisan keamanan pertama pada API: menyimpan password dengan hash, menerbitkan dan memverifikasi token JWT, middleware autentikasi, serta kontrol akses berbasis peran untuk membedakan hak akses pengguna.

API yang melayani data pengguna tidak boleh membiarkan siapa pun mengaksesnya. Di sinilah autentikasi dan otorisasi bekerja: autentikasi membuktikan siapa kalian, otorisasi menentukan apa yang boleh kalian lakukan.
Episode 11 membangun keduanya secara praktis dengan paket yang umum di ekosistem Node.js: bcryptjs untuk hashing password, jsonwebtoken untuk token, dan middleware Express untuk memverifikasi. Kalian akan mengamankan endpoint, lalu membedakan akses berdasarkan peran pengguna.
Menyimpan password dalam teks polos adalah bencana yang menunggu terjadi. Praktik yang benar: simpan hash — hasil fungsi satu arah yang tidak bisa dibalik menjadi password asli. bcryptjs menyediakan hashing dengan salt otomatis dan cost factor:
npm install bcryptjs jsonwebtokennpm install bcryptjs jsonwebtoken menambahkan kedua paket sekaligus. Bcrypt dipilih karena lambat secara sengaja — justru itulah kekuatannya, memperlambat serangan brute force.
import bcrypt from "bcryptjs";
const hash = await bcrypt.hash("rahasia123", 10);
console.log(hash);
const cocok = await bcrypt.compare("rahasia123", hash);
console.log(cocok);bcrypt.hash("rahasia123", 10) menghasilkan string hash dengan cost factor 10, dan bcrypt.compare(password, hash) memverifikasi tanpa menyimpan atau membaca password asli. Simpan hash di database — jika database bocor, password pengguna tetap aman.
JWT (JSON Web Token) adalah cara stateless untuk membawa identitas: token berisi header, payload, dan signature, disandikan dalam tiga bagian yang dipisahkan titik. Karena ditandatangani, isinya tidak bisa diubah tanpa sepengetahuan server.
import jwt from "jsonwebtoken";
const token = jwt.sign(
{ userId: 42, role: "admin" },
process.env.JWT_SECRET,
{ expiresIn: "1h" },
);
const payload = jwt.verify(token, process.env.JWT_SECRET);
console.log(payload.userId, payload.role);jwt.sign(payload, secret, { expiresIn: "1h" }) menerbitkan token yang kedaluwarsa dalam satu jam, dan jwt.verify memeriksa keaslian serta kelayakannya. Nilai process.env.JWT_SECRET wajib disimpan di environment variable — jangan pernah hardcode di kode, karena kita akan bahas di episode 12.
Klien mengirim token di header Authorization dengan format Bearer <token>. Middleware autentikasi memeriksa header, memverifikasi token, lalu menempelkan identitas ke req.user:
function auth(req, res, next) {
const header = req.headers.authorization;
if (!header || !header.startsWith("Bearer ")) {
return res.status(401).json({ error: "Token tidak ditemukan" });
}
try {
req.user = jwt.verify(header.slice(7), process.env.JWT_SECRET);
next();
} catch {
return res.status(401).json({ error: "Token tidak valid" });
}
}header.slice(7) mengambil token setelah kata Bearer . Jika token hilang, kadaluwarsa, atau rusak, middleware membalas 401 dan menghentikan rantai. Jika valid, req.user berisi payload yang siap dipakai handler berikutnya.
Tempelkan auth pada route yang butuh proteksi:
app.get("/api/profil", auth, (req, res) => {
res.json({ userId: req.user.userId });
});app.get("/api/profil", auth, ...) menyisipkan middleware auth di antara definisi route dan handler — hanya request dengan token valid yang sampai ke handler. Route publik seperti login tetap tanpa proteksi.
Autentikasi hanya menjawab siapa kalian. Otorisasi menjawab apa yang boleh kalian lakukan. Ketika payload JWT memuat role, buat middleware kedua untuk memeriksa peran:
function role(peran) {
return (req, res, next) => {
if (req.user.role !== peran) {
return res.status(403).json({ error: "Akses ditolak" });
}
next();
};
}
app.delete("/api/pengguna/:id", auth, role("admin"), (req, res) => {
res.json({ terhapus: req.params.id });
});Pola role("admin") mengembalikan middleware yang membandingkan req.user.role dengan peran yang diizinkan. Perbedaan kode penting: 401 untuk belum terautentikasi, 403 untuk sudah login tapi tidak berhak. Endpoint penghapusan pengguna di atas hanya boleh dijalankan admin.
JWT cocok untuk API dan aplikasi stateless. Untuk aplikasi web tradisional, session berbasis cookie sering lebih sederhana — kita bandingkan keduanya di episode 16. Kunci di episode ini: autentikasi dan otorisasi adalah dua lapis terpisah, masing-masing punya middleware sendiri, dan keduanya mudah diuji secara independen.
Inti yang harus dibawa pulang:
JWT_SECRET disimpan di environment variable, tidak di kode.auth memverifikasi token dan mengisi req.user.401 berarti belum login; 403 berarti tidak berhak.role("admin") membatasi endpoint untuk peran tertentu.Di episode 12 selanjutnya kita akan membahas logging, environment config, dan pengaturan runtime — memuat konfigurasi dari file .env, membedakan NODE_ENV, logging terstruktur dengan pino, serta level logging yang tepat untuk produksi. Konfigurasi yang rapi adalah syarat aplikasi yang bisa di-deploy.