Apa Itu JWT dan Cara Men-decode-nya dengan Aman
JSON Web Token muncul di mana-mana dalam pengembangan web modern — header otentikasi, alur OAuth, kunci API, manajemen sesi. Jika Anda pernah bekerja dengan API apa pun yang memerlukan token Bearer, Anda sudah menggunakan JWT. Tetapi sebagian besar pengembang memperlakukannya sebagai blob buram dan jarang melihat ke dalamnya. Memahami struktur JWT, apa arti setiap bagian, dan cara men-decode satu tanpa membuat kesalahan keamanan membutuhkan waktu sekitar lima belas menit. Panduan ini mencakup semuanya.
Anatomi JWT
Setiap JWT adalah string dari tiga segmen yang di-encode Base64URL yang dipisahkan oleh titik:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImlzcyI6Imh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbSIsImF1ZCI6Imh0dHBzOi8vYXBpLmV4YW1wbGUuY29tIiwiZXhwIjoxNzQ3MDAwMDAwLCJpYXQiOjE3NDY5OTY0MDAsInNjb3BlIjoicmVhZDp1c2VycyJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c Format-nya adalah header.payload.signature. Setiap segmen meng-encode informasi yang berbeda.
Header
Segmen pertama adalah header. Setelah didekode, contoh di atas menjadi:
{
"alg": "RS256",
"typ": "JWT"
} alg menentukan algoritma yang digunakan untuk menandatangani token — RS256 berarti RSA dengan SHA-256. typ mengidentifikasi tipe token. Kedua field ini adalah minimum; beberapa token juga menyertakan kid (key ID) untuk memberi tahu verifier kunci publik mana yang harus digunakan ketika beberapa kunci sedang dalam rotasi.
Payload
Segmen kedua adalah payload — data sebenarnya. Setelah didekode:
{
"sub": "user_123",
"iss": "https://auth.example.com",
"aud": "https://api.example.com",
"exp": 1747000000,
"iat": 1746996400,
"scope": "read:users"
} Payload berisi claim: pernyataan tentang entitas yang diwakili token. Beberapa claim distandarisasi (disebut registered claim); yang lain spesifik aplikasi (disebut private claim). Payload di-encode Base64URL, bukan dienkripsi. Siapa pun yang mendapatkan string token dapat membaca setiap claim di dalamnya.
Tanda Tangan
Segmen ketiga adalah tanda tangan. Ia diproduksi dengan mengambil header dan payload yang di-encode, menggabungkannya dengan titik, lalu menandatangani hasilnya dengan kunci rahasia atau kunci privat yang ditentukan di alg:
signature = sign(
base64url(header) + "." + base64url(payload),
secretOrPrivateKey
) Tanda tangan memungkinkan pihak mana pun dengan kunci publik yang sesuai (atau kunci rahasia, untuk algoritma simetris) memverifikasi bahwa token diterbitkan oleh sumber tepercaya dan bahwa baik header maupun payload tidak dimodifikasi setelah penerbitan. Satu karakter yang berubah di payload membatalkan tanda tangan sepenuhnya.
Cara Men-decode JWT
Men-decode berbeda dari memverifikasi. Men-decode hanya membaca data di dalam token. Memverifikasi mengkonfirmasi bahwa token otentik dan belum kedaluwarsa. Anda harus selalu memverifikasi di kode produksi; men-decode saja berguna untuk debugging.
Langkah 1: Pisahkan token
Pisahkan string JWT pada karakter .. Anda akan mendapatkan tiga segmen. Jika Anda mendapatkan kurang dari tiga, token tersebut salah bentuk.
Langkah 2: Decode header dan payload
Lakukan Base64URL decode pada masing-masing dari dua segmen pertama. Base64URL seperti Base64 standar tetapi menggunakan - alih-alih + dan _ alih-alih /, tanpa karakter padding. Setelah didekode, Anda dapat mem-parse setiap segmen sebagai JSON.
Langkah 3: Parse dan periksa
Baca claim. Periksa exp (kedaluwarsa) terhadap Unix timestamp saat ini. Lihat iss dan aud untuk mengkonfirmasi token dimaksudkan untuk aplikasi Anda. Jangan mempercayai claim apa pun sampai Anda memverifikasi tanda tangan.
Untuk pemeriksaan cepat selama pengembangan, gunakan JWT Decoder. Ia berjalan sepenuhnya di peramban Anda — token Anda tidak pernah meninggalkan perangkat Anda. Anda juga dapat men-decode segmen base64 secara manual dengan encoder/decoder Base64 jika Anda ingin melihat byte mentah. Untuk memverifikasi tanda tangan dalam script uji, generator HMAC memungkinkan Anda mereproduksi tanda tangan HS256 tanpa menulis kode.
Langkah 4: Verifikasi tanda tangan dalam kode
Di produksi, selalu verifikasi tanda tangan menggunakan library yang dibangun untuk bahasa Anda. Jangan mengimplementasikan verifikasi tanda tangan dengan tangan. Opsi populer termasuk jose atau jsonwebtoken untuk Node.js, PyJWT untuk Python, golang-jwt/jwt untuk Go, dan nimbus-jose-jwt untuk Java.
Selalu sebarkan algoritma secara eksplisit. Jangan pernah biarkan library menyimpulkan algoritma dari header token.
Claim Standar (Registered Claim)
RFC 7519 mendefinisikan sekumpulan nama claim terdaftar. Ini tidak diperlukan, tetapi ketika ada, mereka harus mengikuti semantik standar.
iss — Issuer
Entitas yang membuat dan menandatangani token. Biasanya sebuah URL yang mengidentifikasi server otorisasi (misalnya, https://auth.example.com). Verifier harus memeriksa bahwa iss cocok dengan nilai yang diharapkan dan menolak token dari issuer yang tidak dikenal.
sub — Subject
Principal yang diwakili token — biasanya ID pengguna, nama service account, atau pengenal perangkat. Nilai harus unik dalam konteks issuer. Aplikasi Anda menggunakan sub untuk mengidentifikasi pengguna mana yang menjadi pemilik permintaan.
aud — Audience
Penerima yang dimaksudkan dari token. Jika pengenal API Anda adalah https://api.example.com, token yang diterbitkan untuk layanan lain harus ditolak. Gagal memvalidasi aud memungkinkan penyerang menggunakan kembali token yang diperoleh dari satu layanan pada layanan yang berbeda.
exp — Expiration Time
Sebuah Unix timestamp setelahnya token tidak boleh diterima. Selalu validasikan exp. Sebuah token tanpa kedaluwarsa secara efektif hidup selamanya — jika dicuri, penyerang memiliki akses tak terbatas.
iat — Issued At
Unix timestamp ketika token dibuat. Berguna untuk mendeteksi token yang secara teknis belum kedaluwarsa tetapi mencurigakan lama. Anda dapat menggunakan iat untuk menegakkan usia token maksimum independen dari exp.
nbf — Not Before
Unix timestamp sebelumnya token tidak boleh diterima. Kurang umum daripada exp, tetapi berguna ketika menerbitkan token di muka — misalnya, sebuah tugas terjadwal yang tidak boleh dimulai sampai waktu tertentu.
jti — JWT ID
Pengenal unik untuk token. Memungkinkan issuer untuk mencegah serangan replay token dengan menyimpan nilai jti yang digunakan dan menolak token dengan ID duplikat. Diperlukan ketika Anda memerlukan token sekali pakai, seperti tautan reset password.
Jebakan Keamanan
Implementasi JWT memiliki sejarah kerentanan halus. Ini adalah yang paling penting untuk dipahami sebelum mengirim kode yang menerima JWT.
Serangan "alg: none"
Beberapa library JWT dari hari-hari awal standar akan menerima token yang menentukan "alg": "none" di header-nya. Seorang penyerang dapat mengambil token valid apa pun, mengganti algoritma dengan none, menghapus tanda tangan, dan library akan menerimanya sebagai sepenuhnya valid — tidak ada tanda tangan yang diperlukan.
Perbaikannya: selalu tentukan algoritma yang diharapkan secara eksplisit ketika memanggil fungsi verifikasi Anda. Perlakukan token apa pun yang mengklaim alg: none sebagai tidak valid. Sebagian besar library modern telah mengatasi ini, tetapi layak untuk mengkonfirmasi default library Anda sebelum naik ke produksi.
Kebingungan Algoritma (Downgrade RS256 ke HS256)
Beberapa library yang mendukung kedua algoritma akan menggunakan field alg di header token untuk memutuskan cara memverifikasi. Seorang penyerang dapat mengubah algoritma menjadi HS256, lalu menandatangani token menggunakan kunci publik server sebagai rahasia HMAC. Server, melihat HS256, akan memverifikasi terhadap kunci publik dan menerima token palsu.
Perbaikannya sama: kunci algoritma di kode verifikasi Anda. Jangan pernah biarkan header token mempengaruhi algoritma mana yang digunakan untuk verifikasi.
Menerima Token Kedaluwarsa
Tidak memvalidasi exp adalah kelalaian umum — terkadang diperkenalkan ketika pengembang menambahkan periode tenggang yang tumbuh tanpa batas, atau ketika jalur kode validasi dilewati di sebuah cabang kode. Perlakukan token kedaluwarsa sama dengan token yang hilang: tolak dengan 401 dan minta klien untuk melakukan otentikasi ulang atau menggunakan refresh token.
Data Sensitif di Payload
Payload di-encode Base64URL, bukan dienkripsi. Siapa pun yang mencegat token dapat men-decode-nya. Jangan letakkan password, nomor kartu kredit, nomor jaminan sosial, atau data sensitif lainnya di payload. Jika Anda perlu mengirim claim sensitif dengan aman, gunakan token JWE (JSON Web Encryption), yang mengenkripsi payload. JWT yang ditandatangani dengan JWS (kasus umum) hanya menjamin otentisitas, bukan kerahasiaan.
Validasi Audience yang Hilang
Melewati validasi aud berarti token yang diterbitkan untuk Layanan A dapat diputar ulang di Layanan B — selama kedua layanan berbagi kunci penandatanganan yang sama atau mempercayai issuer yang sama. Dalam arsitektur multi-layanan, selalu validasikan bahwa audience token cocok dengan pengenal layanan Anda.
Praktik Terbaik untuk 2026
Pilih RS256 untuk Sebagian Besar Aplikasi
RS256 menggunakan kunci privat untuk menandatangani dan kunci publik untuk memverifikasi. Hanya server otorisasi yang memegang kunci privat. Setiap layanan dapat memverifikasi token menggunakan kunci publik, yang dapat dipublikasikan secara terbuka (sering kali via endpoint JWKS). Jika layanan individual mana pun terkompromi, penyerang mendapatkan kemampuan untuk memverifikasi token — tetapi tidak untuk memalsukan yang baru.
HS256 menggunakan satu rahasia bersama untuk penandatanganan dan verifikasi. Setiap layanan yang dapat memverifikasi token juga dapat membuatnya. Dalam pengaturan microservice, berbagi rahasia di banyak layanan meningkatkan blast radius dari pelanggaran.
Jaga Access Token Tetap Berumur Pendek
Tidak ada mekanisme pencabutan bawaan untuk JWT — setelah diterbitkan, token valid sampai kedaluwarsa (kecuali Anda mengimplementasikan blocklist, yang memperkenalkan kembali state sisi-server). Waktu kedaluwarsa pendek (15 menit hingga 1 jam) membatasi jendela kerusakan jika token dicuri. Pasangkan access token dengan refresh token berumur panjang yang disimpan di cookie HttpOnly yang aman, bukan di localStorage.
Gunakan Rotasi Refresh Token
Ketika klien menggunakan refresh token untuk mendapatkan access token baru, terbitkan refresh token baru dan batalkan yang lama. Dengan cara ini, refresh token yang dicuri terdeteksi pada saat berikutnya klien yang sah mencoba menggunakan yang asli: server melihat refresh token yang digunakan kembali dan dapat mencabut seluruh sesi. Pola ini dijelaskan di RFC 6819 dan didukung secara luas oleh server otorisasi modern.
Publikasikan Endpoint JWKS
Sebuah endpoint JSON Web Key Set (JWKS) (/.well-known/jwks.json berdasarkan konvensi) memublikasikan kunci publik penandatanganan Anda dalam format standar. Layanan lain dapat mengambil JWKS dan memverifikasi token tanpa diberi kunci out-of-band. Ini juga membuat rotasi kunci menjadi lurus: tambahkan kunci baru ke JWKS, mulai menandatangani dengannya, lalu hapus kunci lama setelah semua token yang ada kedaluwarsa.
Rotasikan Kunci Secara Berkala
Bahkan jika kunci privat Anda tidak pernah terkompromi, merotasikan kunci secara berkala membatasi jendela selama mana kunci yang dicuri dapat digunakan untuk memalsukan token. Gunakan kid di header JWT Anda untuk merujuk ke kunci penandatanganan, sehingga verifier dapat memilih kunci publik yang tepat dari JWKS Anda tanpa merusak token yang ada selama rotasi.
Validasikan Setiap Claim
Periksa iss, aud, exp, dan nbf pada setiap permintaan. Jangan melewatkan satu pun dari ini karena mereka tampak redundan dalam pengaturan Anda — kondisi yang membuat mereka tampak tidak perlu hari ini persis adalah kondisi yang berubah selama insiden.
JWT vs. Cookie Sesi
JWT dan sesi sisi-server memecahkan masalah yang sama — mempertahankan state otentikasi melintasi HTTP yang stateless — tetapi dengan trade-off yang berbeda.
JWT mandiri. Server tidak perlu melakukan query ke basis data untuk memvalidasi permintaan. Ini menjadikannya menarik untuk sistem terdistribusi dan API yang dikonsumsi oleh klien mobile atau pihak ketiga. Kelemahannya adalah pencabutan memerlukan blocklist (yang memperkenalkan kembali state sisi-server) atau mentolerir umur tersisa dari token yang terkompromi.
Cookie sesi divalidasi-server. Server menyimpan state sesi dan dapat mencabut akses secara instan dengan menghapus sesi. Cookie dengan flag HttpOnly dan Secure dilindungi dari akses JavaScript dan intersepsi jaringan. Kelemahannya adalah setiap permintaan memerlukan pencarian basis data, yang dapat menjadi bottleneck dalam skala.
Untuk aplikasi web tradisional dengan halaman yang dirender server dan satu backend, cookie sesi tetap menjadi pilihan yang solid dan lebih sederhana. Untuk API yang dikonsumsi oleh beberapa klien, arsitektur microservice, dan aplikasi mobile, JWT dengan kedaluwarsa pendek dan rotasi refresh token adalah opsi yang lebih praktis.
Decode Token Anda
Cara tercepat untuk memeriksa JWT adalah dengan menempelkannya ke JWT Decoder. Ia memisahkan token, men-decode header dan payload, dan merender claim dalam format yang dapat dibaca — semuanya tanpa mengirim token Anda ke mana pun. Jika Anda perlu meng-encode atau men-decode string Base64URL mentah secara manual, encoder/decoder Base64 menangani baik varian standar maupun URL-safe. Untuk memverifikasi tanda tangan HMAC dalam script uji, generator HMAC memungkinkan Anda mereproduksi tanda tangan HS256 dan membandingkannya dengan apa yang dikandung token Anda.
Untuk spesifikasi lengkap, lihat RFC 7519 (JWT) dan contoh interaktif di jwt.io.