authjwttokenbearerMahir4 mnt baca

Bearer Token & JWT: Standar Login API Modern

Cara kerja bearer token, anatomi JWT (header.payload.signature), dan praktik penyimpanan yang aman.

Kartu akses hotel yang kedaluwarsa sendiri

Check-in hotel, kamu dapat kartu akses kamar yang mati otomatis saat checkout. Tidak perlu dikembalikan, tidak perlu dimatikan manual. JWT (JSON Web Token) bekerja mirip: token yang membawa identitasmu dan kedaluwarsa sendiri, dipakai lewat skema Bearer di header Authorization.

Kenapa token mengalahkan session

Session klasik menyimpan data login di server, sehingga setiap request harus mengecek database. JWT membalik logikanya: semua info penting (id user, peran, waktu kedaluwarsa) ditulis DI DALAM token dan ditandatangani secara kriptografis. Server cukup memverifikasi tanda tangan, tanpa menyimpan apa pun. Hasilnya: stateless, mudah diskalakan, dan cocok untuk API yang dipakai banyak klien (web, mobile, pihak ketiga).

Contoh 1: anatomi JWT

Token JWT punya tiga bagian dipisah titik:

eyJhbGciOiJIUzI1NiJ9.eyJpZCI6NDIsInJvbGUiOiJhZG1pbiJ9.tanda-tangan
  • Header: algoritma tanda tangan.
  • Payload: data, misalnya {"id": 42, "role": "admin", "exp": 1728384000}. Perhatian: payload hanya di-encode, TIDAK dienkripsi, jadi jangan taruh data rahasia di sini.
  • Signature: tanda tangan yang membuktikan token tidak dipalsukan. Hanya server pemilik secret key yang bisa membuatnya.

Contoh 2: alur login sampai request

Login dulu untuk mendapatkan token:

http
POST /api/login HTTP/1.1
Host: toko.contoh.id
Content-Type: application/json

{"email": "[email protected]", "password": "rahasia"}
http
HTTP/1.1 200 OK

{"token": "eyJhbGciOi..."}

Lalu pakai token di setiap request:

javascript
const response = await fetch("https://toko.contoh.id/api/profil", {
  headers: { "Authorization": "Bearer " + token }
});

Kata Bearer berarti "siapa pun yang membawa token ini dianggap pemiliknya." Makanya token harus dijaga seperti password.

Kesalahan umum

Salah: menyimpan JWT di localStorage untuk aplikasi sensitif. Rentan dicuri lewat XSS. Yang benar: untuk keamanan maksimal pakai httpOnly cookie; localStorage hanya untuk kasus risiko rendah.

Salah: menaruh data rahasia di payload. Payload bisa di-decode siapa pun. Yang benar: hanya id dan peran, bukan password atau data pribadi sensitif.

Salah: membuat token tanpa kedaluwarsa. Token abadi yang bocor memberi akses selamanya. Yang benar: access token berumur pendek (15 menit - 1 jam) plus refresh token untuk memperbarui.

Salah: tidak menangani 401 dengan refresh. Token kedaluwarsa lalu aplikasi logout paksa padahal bisa diperbarui diam-diam. Yang benar: saat 401, coba refresh token dulu, baru anggap sesi berakhir.

Struktur payload yang baik

Contoh payload JWT yang dirancang benar:

json
{
  "sub": "user_42",
  "role": "kasir",
  "iat": 1728384000,
  "exp": 1728387600
}
  • sub (subject): siapa pemilik token, pakai ID bukan email (email bisa berubah).
  • role: untuk otorisasi cepat tanpa query database.
  • iat/exp: kapan dibuat dan kedaluwarsa (wajib ada).

Yang TIDAK boleh ada: password, nomor KTP, atau data sensitif lain. Ingat: payload hanya di-encode base64, siapa pun bisa membacanya. Token yang baik itu minimalis.

Catatan teknis: Verifikasi JWT selalu di sisi server dengan secret key yang tidak pernah dibagikan. Jangan pernah memverifikasi token hanya di frontend: itu seperti memeriksa KTP dengan melihat fotokopinya saja.

Tantangan

Bedah JWT asli

Ambil contoh JWT ini (token dummy untuk latihan):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NywibmFtYSI6IkJ1ZGkiLCJyb2xlIjoic2lzd2EiLCJleHAiOjE4MDAwMDAwMDB9.dummy
  1. Tulis fungsi bacaPayload(token) yang mengembalikan object payload-nya.
  2. Dari payload, jawab: siapa nama usernya, apa role-nya, dan kapan token ini kedaluwarsa (convert exp ke tanggal dengan new Date(exp * 1000))?
  3. Jelaskan kenapa payload JWT tidak boleh berisi data rahasia seperti password.
<!doctype html>
<html>
<head>
<meta charset="utf-8" />

</head>
<body>
<h1>Halo JS</h1>
<p>Buka console preview untuk melihat output.</p>
<script src="index.js"></script>
</body>
</html>