JWT (JSON Web Token) adalah string berisi tiga bagian base64url, header.payload.signature, yang diberikan server kepada user saat login dan dicek di setiap request sesudahnya. Signature-nya membuktikan bahwa server yang menerbitkan token dan tidak ada yang mengubahnya, tetapi payload-nya hanya di-encode, tidak dienkripsi, jadi siapa pun bisa membacanya. Di Node.js kamu membuatnya dengan new SignJWT(payload).sign(secret) dari package jose dan mengeceknya dengan jwtVerify(token, secret).
Hasilnya 3 parts, lalu user-42 admin: jwtVerify mengecek signature dan masa berlakunya lalu mengembalikan payload-nya. Ubah satu karakter dari secret yang diberikan ke jwtVerify lalu jalankan lagi: verifikasinya gagal dengan signature verification failed.
Apa isi sebuah JWT
Header dan payload-nya adalah JSON, di-encode dengan base64url. Men-decode-nya tidak butuh key, itulah sebabnya JWT tidak boleh berisi password atau hal rahasia lainnya.
Dua baris pertama mencetak {"alg":"HS256"} dan {"name":"Ada","role":"editor"}, yang bisa dibaca siapa pun yang memegang token-nya. Signature-nya (43 karakter untuk HS256) yang mencegah mereka mengubahnya: ganti editor menjadi admin dan signature-nya tidak cocok lagi.
| Bagian | Berisi | Rahasia? |
|---|---|---|
| Header | Algoritmanya, seperti HS256 | Tidak, bisa dibaca |
| Payload | Claim: sub (id user), exp (kedaluwarsa), iat (waktu terbit), field milikmu sendiri | Tidak, bisa dibaca |
| Signature | Signature HMAC atau RSA dari dua bagian pertama | Butuh key untuk membuatnya |
Masa berlaku dan verifikasi yang gagal
setExpirationTime('15m') menulis claim exp, dan jwtVerify menolak token yang sudah melewatinya. Setiap penolakan adalah error dengan code, jadi kamu bisa membedakan token yang kedaluwarsa dari token palsu.
Pengecekan pertama gagal dengan ERR_JWT_EXPIRED dan yang kedua, yang signature-nya diubah, dengan ERR_JWS_SIGNATURE_VERIFICATION_FAILED. Bagi API-mu keduanya berarti sama (jawab 401), tetapi mencatat kodenya membantu saat debugging.
Melindungi route Express dengan Bearer token
Client login sekali, menyimpan token-nya, lalu mengirimnya di header Authorization sebagai Bearer <token>. Sebuah middleware memverifikasinya dan menaruh payload-nya di req.user untuk route.
Request pertama, GET /me tanpa token, mendapat 401 dan Missing token. Kirim POST /login dengan body {"username": "ada", "password": "lovelace"}, salin token dari response-nya, lalu kirim GET /me lagi dengan header Authorization: Bearer <token>: jawabannya {"id":"user-1","name":"ada"}.
Package jsonwebtoken
jsonwebtoken (npm install jsonwebtoken) adalah pilihan umum lainnya. sign dan verify miliknya synchronous (dengan callback opsional), bukan mengembalikan promise:
const jwt = require('jsonwebtoken');
const token = jwt.sign({ role: 'admin' }, process.env.JWT_SECRET, {
subject: 'user-42',
expiresIn: '1h',
});
const payload = jwt.verify(token, process.env.JWT_SECRET); // throws if invalid
Pakai jose untuk kode baru: package ini tidak punya dependency dan juga berjalan di edge runtime dan browser. Token dari kedua library adalah JWT standar, jadi yang satu bisa memverifikasi token yang ditandatangani yang lain.
Kesalahan umum
Memakai decode alih-alih verify. jwt.decode dan decodeJwt membaca payload tanpa mengecek signature-nya, jadi token palsu bisa lolos. Percayai hanya apa yang dikembalikan verify.
Secret yang pendek atau ikut di-commit. Secret HS256 yang bisa ditebak membuat penyerang bisa menandatangani token mereka sendiri. Pakai paling sedikit 32 byte acak, baca dari process.env, dan jangan pernah commit.
Token yang tidak pernah kedaluwarsa. Tanpa exp, token yang bocor berlaku selamanya. Selalu atur masa berlaku.
Pertanyaan yang sering diajukan
Di mana client sebaiknya menyimpan JWT?
Di aplikasi browser, cookie HttpOnly dan Secure paling aman, karena script halaman tidak bisa membacanya. localStorage lebih sederhana, tetapi script apa pun di halaman itu, termasuk yang disusupkan, bisa membaca token-nya. Aplikasi mobile memakai penyimpanan aman milik platformnya.
Bagaimana cara logout user dengan JWT?
Server tidak bisa membatalkan token yang sudah ditandatanganinya; token itu tetap berlaku sampai kedaluwarsa. Hapus di client, buat access token berumur pendek, dan kalau kamu butuh logout seketika, simpan daftar id token yang dicabut (jti) di server dan cek di setiap request.
HS256 atau RS256?
HS256 memakai satu secret bersama untuk sign dan verify, cocok untuk satu backend. RS256 melakukan sign dengan private key dan verify dengan public key, jadi service lain bisa mengecek token tanpa bisa membuatnya.
Berapa lama JWT sebaiknya berlaku?
Access token biasanya berlaku 5 sampai 60 menit. Untuk sesi yang lebih panjang, pasangkan dengan refresh token yang disimpan lebih hati-hati, yang ditukar client dengan access token baru.