Topik:
 

Apa itu JSON Web Token (JWT)? Panduan Lengkap

Oleh: Hobon.id (31/07/2026)
Apa itu JSON Web Token (JWT)? Panduan LengkapHampir setiap aplikasi web dan seluler modern perlu menjawab pertanyaan yang tampak sederhana pada setiap permintaan yang diterimanya, yaitu siapa yang mengajukan permintaan ini, dan apa saja hak akses mereka? Menjawab pertanyaan tersebut secara andal, cepat, dan dalam skala besar—meliputi browser web, aplikasi seluler, single-page application, serta puluhan microservices yang saling terhubung—merupakan salah satu tantangan rekayasa paling mendasar dalam membangun sistem software yang kompleks; sebuah tantangan yang sudah ada jauh sebelum kemunculan JSON Web Token (JWT).

JWT—yang biasanya dilafalkan sebagai "jot"—telah menjadi salah satu solusi paling populer untuk masalah ini dan kerap ditemukan dalam sistem autentikasi modern, yaitu saat kita masuk ke aplikasi web dan tetap dalam status logged-in sembari berpindah antarhalaman; saat aplikasi seluler mengenali kita di berbagai sesi tanpa mengharuskan kita memasukkan ulang kata sandi setiap saat; serta saat satu layanan internal dalam infrastruktur perusahaan perlu membuktikan identitasnya kepada layanan lain yang sedang dipanggilnya. Memahami hakikat JWT—bukan sekadar mengetahuinya sebagai "token untuk autentikasi," melainkan memahami struktur isinya, cara kerja mekanisme keamanan yang menjamin keandalannya, serta potensi penyalahgunaannya—merupakan pengetahuan krusial bagi setiap developer yang membangun atau memelihara sistem yang perlu mengenali identitas penggunanya.
Advertisement:

Apa Sebenarnya JWT Itu


JSON Web Token (JWT) adalah format yang ringkas, aman untuk URL, dan mandiri untuk merepresentasikan sekumpulan klaim—yaitu pernyataan mengenai suatu entitas, biasanya pengguna—yang dapat ditransmisikan di antara dua pihak serta diverifikasi secara kriptografis untuk memastikan keaslian dan integritasnya (tidak diubah). Format ini didefinisikan oleh standar terbuka RFC 7519 yang diterbitkan oleh Internet Engineering Task Force; artinya, JWT bukanlah teknologi eksklusif milik perusahaan tertentu, melainkan sebuah spesifikasi yang dapat diimplementasikan oleh sistem mana pun dan memungkinkan interoperabilitas antarberbagai sistem.

Sifat paling krusial dari JWT—yang membuatnya benar-benar bermanfaat dan bukan sekadar cara lain untuk memformat data—adalah sifatnya yang mandiri dan dapat diverifikasi secara independen. Setelah server menerbitkan JWT kepada klien (biasanya setelah klien berhasil masuk menggunakan nama pengguna dan kata sandi), token itu sendiri memuat informasi yang cukup bagi server mana pun yang memiliki kunci verifikasi yang tepat untuk memastikan dua hal tanpa perlu melakukan pencarian di database, yaitu pertama, bahwa token tersebut benar-benar diterbitkan oleh sumber tepercaya dan tidak diubah sejak penerbitannya; dan kedua, klaim spesifik mengenai pengguna yang dimuat dalam token tersebut, seperti ID pengguna, peran, atau waktu kedaluwarsa token.

Sifat mandiri dan kemampuan verifikasi independen inilah yang membedakan JWT dari pendekatan session-token tradisional sebelumnya. Pada pendekatan lama, server harus menyimpan catatan sisi-server untuk setiap sesi aktif dan memeriksa catatan tersebut pada setiap permintaan untuk mengidentifikasi pengguna yang mengajukan permintaan. JWT menghilangkan kebutuhan akan pemeriksaan tersebut, yang memiliki implikasi signifikan terhadap skalabilitas sistem.

Penting untuk meluruskan satu hal yang sering menimbulkan kebingungan, yaitu JWT tidak secara inheren terenkripsi. Secara default, siapa pun yang memiliki salinan JWT dapat membaca setiap klaim di dalamnya tanpa memerlukan kunci rahasia sama sekali. Jaminan keamanan yang diberikan JWT berkaitan dengan integritas dan autentisitas—bukti bahwa konten tidak diubah dan bukti mengenai siapa penerbitnya—bukan mengenai kerahasiaan data. Perbedaan ini memiliki konsekuensi praktis nyata.


Tiga Bagian JWT


JWT adalah sebuah string tunggal yang terdiri dari tiga bagian berbeda—masing-masing dienkode secara terpisah—yang digabungkan dengan tanda titik. Jika kita melihat JWT yang sebenarnya, strukturnya secara visual dapat dikenali sebagai tiga potongan karakter yang tampak acak dan dipisahkan oleh dua titik—contohnya seperti `eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c`.


Header


Bagian pertama adalah header, sebuah objek JSON kecil yang mendeskripsikan token itu sendiri, yaitu algoritma apa yang digunakan untuk menandatanganinya (biasanya direpresentasikan oleh kolom `alg`, dengan nilai seperti HS256 atau RS256) dan, secara opsional, jenis tokennya, yang biasanya berupa JWT. Header ini dienkode menggunakan Base64URL—varian pengodean Base64 standar yang aman untuk URL—yang dipilih secara khusus karena menghasilkan keluaran yang dapat disertakan dengan aman dalam URL, header HTTP, dan cookie tanpa memerlukan escaping tambahan.


Payload


Bagian kedua adalah payload, yaitu objek JSON yang memuat claims yang sebenarnya, yaitu informasi substantif yang ditegaskan oleh token tersebut. Klaim-klaim ini terbagi ke dalam tiga kategori informal. Registered claims adalah sekumpulan kecil nama klaim standar yang telah ditetapkan sebelumnya dan memiliki makna spesifik yang sudah dipahami secara umum: `iss` (issuer atau penerbit, pihak yang membuat token), `sub` (subject atau subjek, biasanya ID pengguna yang dirujuk oleh token), `aud` (audience atau audiens, pihak yang dituju oleh token), `exp` (expiration time atau waktu kedaluwarsa), `iat` (issued at time atau waktu penerbitan), dan `nbf` (not before, waktu sebelum token dianggap belum berlaku). Public claims adalah nama klaim yang telah didaftarkan dalam registri publik (dikelola melalui IANA JSON Web Token Registry) untuk menghindari konflik penamaan antara sistem berbeda yang ingin menggunakan nama klaim serupa untuk tujuan yang sama. Private claims adalah nama klaim kustom yang disepakati oleh pihak-pihak yang menggunakannya—misalnya, sebuah perusahaan mungkin menambahkan klaim role, klaim tenantId untuk sistem multi-tenant, atau data spesifik aplikasi lainnya yang perlu disertakan.

Sama halnya dengan bagian header, bagian payload dienkode menggunakan format Base64URL dan tidak dienkripsi. Artinya, siapa pun yang mencegat atau memperoleh JWT tersebut dapat melakukan dekode pada bagian ini dan membaca setiap klaim di dalamnya dalam bentuk teks biasa, hanya dengan menggunakan alat dekoder Base64 standar. Inilah alasan mengapa informasi sensitif—tentu saja termasuk kata sandi, namun juga data yang sensitivitasnya mungkin tidak terlalu kentara seperti nama lengkap resmi pengguna, alamat fisik yang spesifik, atau pengenal internal yang tidak ingin Anda ungkapkan—sebaiknya tidak pernah dicantumkan secara langsung di dalam payload JWT, kecuali jika token tersebut juga dienkripsi melalui mekanisme terpisah.


Signature


Bagian ketiga adalah signature, dan inilah komponen yang sesungguhnya membuat keseluruhan token dapat dipercaya, alih-alih sekadar menjadi data yang dapat dibaca manusia, mudah dipalsukan, dan hanya berdasarkan klaim sepihak. Signature ini dihasilkan dengan cara mengambil header dan payload yang telah disandikan, menggabungkannya, lalu memprosesnya menggunakan algoritma penandatanganan kriptografis bersama dengan kunci rahasia (pada penandatanganan simetris) atau kunci privat (pada penandatanganan asimetris).


Cara Kerja Penandatanganan JWT yang Sebenarnya


Saat server menerbitkan JWT, server tersebut menyusun header dan payload, melakukan pengodean Base64URL pada masing-masing bagian, lalu mengambil string `encoded_header + "." + encoded_payload` dan memprosesnya melalui fungsi penandatanganan kriptografis. Proses ini melibatkan kunci rahasia atau kunci privat yang hanya dimiliki oleh server penerbit (dan pihak lain mana pun yang secara eksplisit dipercayainya). Hasil keluaran dari fungsi penandatanganan ini menjadi bagian ketiga dari token tersebut. JWT lengkap yang dikirimkan ke klien merupakan gabungan dari ketiga bagian yang telah dikodekan dengan Base64URL tersebut, yang disatukan menggunakan tanda titik.

Ketika server menerima kembali JWT ini dari klien dan perlu memverifikasinya, proses verifikasi dilakukan dengan menghitung ulang nilai tanda tangan yang seharusnya—berdasarkan header dan payload yang benar-benar diterima—menggunakan kunci rahasia yang sama atau kunci publik yang sesuai. Jika tanda tangan hasil perhitungan ulang tersebut cocok dengan tanda tangan yang tercantum dalam token, server dapat meyakini dua hal, yaitu header dan payload token tidak diubah sejak pertama kali ditandatangani (karena perubahan satu karakter saja pada salah satu bagian akan menghasilkan tanda tangan yang sama sekali berbeda saat dihitung ulang), dan token tersebut benar-benar dibuat oleh pihak yang memiliki kunci penandatanganan yang tepat (karena menghasilkan tanda tangan yang valid tanpa kunci tersebut—dengan asumsi algoritma yang dipilih tepat dan panjang kunci memadai—adalah hal yang mustahil dilakukan secara komputasi).

Inilah keseluruhan model keamanan JWT yang dapat dirangkum dalam satu kalimat, yaitu tanda tangan membuktikan bahwa token tidak dimanipulasi dan membuktikan siapa pembuatnya, tanpa mengharuskan server verifikator untuk pernah melihat token spesifik tersebut sebelumnya atau melakukan pencarian data di database. Inilah karakteristik yang membuat JWT sangat berguna bagi sistem terdistribusi—server mana pun yang memiliki kunci verifikasi yang tepat dapat memvalidasi JWT secara independen, tanpa memerlukan akses bersama ke penyimpanan sesi terpusat.


HMAC vs. RSA/ECDSA: Dua Pendekatan Penandatanganan


HMAC (Hash-based Message Authentication Code)—yang paling umum digunakan bersama SHA-256 dan direpresentasikan dalam header JWT sebagai algoritma HS256—merupakan pendekatan simetris, yaitu kunci rahasia yang sama persis digunakan baik untuk membuat tanda tangan saat token diterbitkan maupun untuk memverifikasi tanda tangan saat token divalidasi kemudian. Pendekatan ini sederhana untuk diimplementasikan dan efisien secara komputasi, serta bekerja dengan baik untuk sistem di mana satu server tunggal (atau sejumlah kecil server tepercaya yang dapat berbagi kunci rahasia yang sama dengan aman) bertindak sebagai satu-satunya pihak yang menerbitkan sekaligus memverifikasi token. Keterbatasan signifikannya adalah siapa pun yang memiliki kunci rahasia untuk memverifikasi token otomatis juga memiliki segala hal yang diperlukan untuk memalsukan token baru yang valid dari nol; artinya, kunci rahasia harus dikelola dengan sangat hati-hati dan tidak boleh didistribusikan secara aman kepada pihak yang hanya perlu memverifikasi token tetapi tidak boleh memiliki kemampuan untuk menerbitkannya.

RSA dan ECDSA—yang direpresentasikan dalam header JWT sebagai algoritma seperti RS256 atau ES256—menggunakan kriptografi asimetris, yaitu kunci privat digunakan untuk membuat tanda tangan, sedangkan kunci publik yang terkait secara matematis namun berbeda digunakan untuk memverifikasinya. Hal yang krusial adalah, memiliki kunci publik saja sudah cukup untuk memverifikasi keaslian token, namun tidak cukup untuk memalsukan token baru yang valid—hanya kunci privat yang dapat melakukannya. Asimetri ini memberikan keunggulan arsitektural yang besar dalam sistem terdistribusi: sebuah layanan autentikasi dapat memegang kunci privat tunggal dan menjadi satu-satunya komponen dalam keseluruhan sistem yang berwenang menerbitkan token, sementara puluhan atau ratusan layanan lain dalam arsitektur microservices dapat masing-masing diberikan salinan kunci publik. Hal ini memungkinkan setiap layanan tersebut memverifikasi token yang masuk secara independen tanpa perlu diberi kepercayaan (atau memiliki kemampuan untuk menyalahgunakan wewenang) untuk menerbitkan token baru sendiri.

Panduan praktis yang dapat diambil dari perbedaan ini sangat jelas, yaitu untuk sistem sederhana yang berjalan pada server tunggal atau sistem dengan keterikatan komponen yang erat, kesederhanaan dan performa HMAC adalah pilihan yang sangat tepat. Untuk sistem apa pun yang melibatkan berbagai layanan independen yang perlu memverifikasi token—situasi standar dalam arsitektur microservices berskala memadai—penandatanganan asimetris menggunakan RSA atau ECDSA merupakan pilihan yang tepat secara arsitektural, karena metode ini memisahkan secara jelas antara hak istimewa untuk menerbitkan token dan hak istimewa untuk sekadar memverifikasinya, yang cakupan kebutuhannya jauh lebih luas.


Autentikasi JWT vs. Berbasis Sesi


Dalam autentikasi berbasis sesi tradisional, saat pengguna berhasil masuk (log in), server membuat catatan sesi—biasanya disimpan dalam database atau penyimpanan in-memory yang cepat seperti Redis—yang memuat identitas pengguna dan data sesi relevan lainnya. Server kemudian menghasilkan pengenal sesi acak yang tidak memiliki makna khusus untuk dikirimkan ke klien, yang biasanya disimpan dalam cookie. Pada setiap permintaan berikutnya, klien mengirimkan kembali pengenal sesi ini ke server; server lalu mencari catatan sesi yang sesuai di penyimpanan sesinya untuk menentukan siapa yang melakukan permintaan dan apakah status masuk mereka masih valid. Model ini memiliki keunggulan nyata yang sering kali kurang dihargai, yaitu karena status sesi yang sebenarnya tersimpan sepenuhnya di server, mencabut sesi—yaitu mengeluarkan pengguna (log out) secara seketika di semua perangkat—semudah menghapus satu catatan tersebut dari penyimpanan sesi. Permintaan berikutnya yang membawa pengenal sesi yang telah dihapus itu akan gagal menemukan catatan yang cocok dan dengan tepat dianggap sebagai permintaan yang tidak terautentikasi.

Autentikasi berbasis JWT menggunakan pendekatan yang sangat berbeda, yaitu alih-alih menyimpan status sesi di server dan memberikan referensi tanpa makna kepada klien untuk pencarian data, server menyandikan informasi sesi yang sebenarnya langsung ke dalam token yang telah ditandatangani dan menyerahkan token mandiri tersebut kepada klien. Karena token ini bersifat mandiri dan dapat diverifikasi secara independen melalui tanda tangannya, permintaan-permintaan berikutnya dapat diautentikasi oleh server mana pun yang mampu memverifikasi tanda tangan tersebut, tanpa perlu melakukan kueri ke penyimpanan sesi terpusat yang digunakan bersama. Sifat stateless (tanpa penyimpanan status sesi di server) ini merupakan keunggulan arsitektural utama JWT, yaitu metode ini menghilangkan langkah pencarian di penyimpanan sesi dari alur kritis setiap permintaan terautentikasi—yang dapat secara signifikan mengurangi latensi maupun beban infrastruktur dalam skala besar—serta sepenuhnya meniadakan kebutuhan akan penyimpanan sesi terpusat yang dapat diakses bersama dalam arsitektur tertentu (terutama arsitektur terdistribusi dan multi-service), di mana pemeliharaan infrastruktur bersama semacam itu justru akan menambah kompleksitas operasional yang nyata.

Konsekuensi yang harus dipertimbangkan adalah bahwa sifat stateless (tanpa penyimpanan status) inilah yang justru membuat pembatalan JWT sebelum masa berlakunya habis menjadi sangat sulit; sebuah kendala yang tidak dihadapi oleh autentikasi berbasis sesi, karena sistem tersebut memang tidak dirancang dengan prinsip stateless sejak awal. Tidak ada satu pendekatan pun yang mutlak lebih unggul dalam segala situasi; keduanya mencerminkan pilihan arsitektur yang melibatkan pertimbangan nyata antara kemudahan operasional dalam skala besar dan kemampuan untuk melakukan pembatalan secara presisi dan seketika.


Alur Umum Autentikasi JWT


Alur ini dimulai ketika pengguna mengirimkan kredensial login mereka—biasanya berupa nama pengguna atau alamat email serta kata sandi—ke endpoint autentikasi. Server memverifikasi kredensial tersebut dengan mencocokkannya terhadap database pengguna; biasanya dilakukan dengan membandingkan kata sandi yang dikirimkan dengan versi hash aman yang disimpan sejak pembuatan akun. Jika kredensial valid, server membuat JWT, yaitu server menyusun payload yang berisi klaim mengenai pengguna yang telah terautentikasi (seperti ID pengguna, peran atau hak akses, serta klaim standar seperti waktu kedaluwarsa), menandatangani payload tersebut menggunakan kunci rahasia atau kunci privat miliknya, lalu mengirimkan token yang dihasilkan kembali ke klien.

Klien—baik berupa browser web yang menjalankan JavaScript, aplikasi seluler, maupun jenis aplikasi klien lainnya—menyimpan token ini dan menyertakannya dalam setiap permintaan berikutnya yang memerlukan autentikasi; hal ini umumnya dilakukan melalui header HTTP `Authorization` dengan format `Authorization: Bearer `.

Saat server menerima permintaan yang memuat header tersebut, server mengekstrak token, memverifikasi tanda tangannya menggunakan kunci yang sesuai, dan—jika tanda tangan valid—memeriksa klaim-klaim dalam token tersebut. Hal terpenting dalam tahap ini adalah memastikan bahwa klaim `exp` (kedaluwarsa) menunjukkan bahwa masa berlaku token belum habis. Jika seluruh proses validasi berhasil, server memercayai klaim yang tertanam dalam token (seperti identitas pengguna, peran, dan sebagainya) tanpa perlu melakukan pencarian tambahan di database untuk memastikan kembali siapa pengirim permintaan tersebut. Selanjutnya, server memproses permintaan itu, dan mungkin menggunakan informasi peran atau hak akses yang ada di dalam token untuk mengambil keputusan otorisasi mengenai tindakan apa yang diizinkan bagi permintaan spesifik tersebut.


Access Token vs. Refresh Token


Terdapat pertentangan mendasar antara aspek keamanan dan kemudahan penggunaan saat menentukan masa berlaku JWT. JWT dengan masa berlaku yang sangat lama memang praktis bagi pengguna karena mereka tidak perlu berulang kali masuk (login), namun hal ini sangat berisiko dari sisi keamanan. Mengingat desain JWT membuatnya sulit untuk dicabut sebelum masa berlakunya habis, token berumur panjang yang dicuri atau bocor akan tetap menjadi kredensial yang sah dan dapat digunakan oleh penyerang selama sisa masa berlakunya—yang bisa jadi sangat lama. Sebaliknya, JWT dengan masa berlaku sangat singkat jauh lebih aman dalam skenario ini karena token yang dicuri akan menjadi tidak berguna dalam hitungan menit; namun, mengharuskan pengguna memasukkan kembali nama pengguna dan kata sandi setiap beberapa menit tentu akan membuat aplikasi praktis tidak dapat digunakan.

Solusi standarnya adalah menerbitkan dua token terpisah saat proses login, bukan hanya satu. Access token adalah JWT dengan masa berlaku yang sengaja dibuat singkat—biasanya antara lima menit hingga satu jam—dan merupakan token yang dikirimkan bersama setiap permintaan API untuk membuktikan identitas pengguna pada permintaan tersebut, persis seperti yang dijelaskan dalam alur di atas. Sementara itu, refresh token adalah kredensial terpisah yang biasanya memiliki masa berlaku jauh lebih lama (berhari-hari, berminggu-minggu, atau bahkan jauh lebih lama lagi pada sistem tertentu). Tujuan utamanya bukanlah untuk mengautentikasi permintaan biasa secara langsung, melainkan khusus untuk ditukarkan—saat access token yang berumur pendek itu habis masa berlakunya—dengan access token yang baru, tanpa mengharuskan pengguna memasukkan kembali nama pengguna dan kata sandi mereka.

Pola dua token ini menghadirkan manfaat praktis dari kedua pendekatan tersebut secara bersamaan, yaitu karena access token memiliki masa berlaku singkat, token yang dicuri hanya memiliki rentang waktu bahaya yang terbatas, sehingga meminimalkan dampak kerusakan yang mungkin ditimbulkan oleh kebocoran token tersebut. Selain itu, karena refresh token—berbeda dengan access token—umumnya tidak diimplementasikan sebagai JWT yang mandiri dan diverifikasi secara stateless, melainkan sebagai pengenal acak yang tidak transparan dan dilacak oleh server dalam database, token ini dapat dicabut secara langsung dan presisi; menghapus catatan database untuk refresh token tertentu akan mencegah token tersebut ditukarkan kembali dengan access token baru secara instan dan permanen, sehingga memberikan kemampuan nyata dan seketika bagi sistem untuk "mengeluarkan (log out) pengguna dari semua sesi saat ini juga"—sesuatu yang tidak dapat dilakukan oleh JWT murni yang bersifat stateless jika berdiri sendiri.


Di Mana JWT Sebaiknya Disimpan pada Sisi Klien


Menyimpan JWT di `localStorage` browser adalah pendekatan yang umum dilakukan, terutama karena penerapannya sederhana dan token mudah diakses oleh JavaScript untuk disertakan dalam permintaan API. Kelemahan signifikannya adalah bahwa apa pun yang dapat diakses oleh JavaScript aplikasi kita juga dapat diakses oleh JavaScript berbahaya yang berhasil dijalankan dalam konteks halaman kita. Artinya, kerentanan cross-site scripting (XSS) di bagian mana pun dari aplikasi kita—bahkan dalam skrip atau library pihak ketiga yang tampaknya tidak terkait namun kita sertakan—dapat memungkinkan penyerang membaca token secara langsung dari `localStorage` dan mencurinya, sehingga mendapatkan akses penuh untuk menyamar sebagai pengguna tersebut selama token yang dicuri masih berlaku.

Menyimpan JWT dalam cookie `HttpOnly`—yaitu cookie yang ditandai secara khusus agar tidak dapat diakses sama sekali oleh JavaScript dan hanya dikirim secara otomatis oleh browser sebagai bagian dari penanganan permintaan HTTP standar—secara signifikan mengurangi risiko XSS yang disebutkan di atas. Hal ini dikarenakan JavaScript berbahaya yang berjalan di halaman tersebut tidak dapat membaca isi cookie bagaimanapun caranya. Namun, hal ini membawa konsekuensi lain yang sama seriusnya, yaitu karena browser kini mengirimkan cookie tersebut secara otomatis pada setiap permintaan ke domain terkait—termasuk permintaan yang mungkin dipicu oleh website pihak ketiga yang berbahaya melalui manipulasi browser pengguna—aplikasi menjadi rentan terhadap serangan cross-site request forgery (CSRF), kecuali jika perlindungan tambahan (biasanya berupa token CSRF yang dibuat secara terpisah, dikombinasikan dengan atribut cookie `SameSite` yang diatur ke `Strict` atau `Lax`) diterapkan secara sengaja bersamaan dengannya.

Jawaban yang benar dan mengutamakan aspek keamanan—yang patut disampaikan secara lugas tanpa bertele-tele—adalah bahwa tidak ada lokasi penyimpanan yang secara bawaan aman sepenuhnya tanpa syarat apa pun. Penggunaan cookie HttpOnly yang disertai perlindungan CSRF yang memadai umumnya dianggap sebagai pilihan standar yang lebih aman, khususnya untuk aplikasi web berbasis browser; hal ini dikarenakan CSRF merupakan masalah yang sudah dipahami dengan baik dan memiliki mekanisme mitigasi yang matang serta teruji, sedangkan kerentanan XSS dapat muncul dari hampir setiap bagian dalam dependency tree aplikasi web modern dan jauh lebih sulit untuk dihilangkan sepenuhnya. Untuk aplikasi seluler native, mekanisme penyimpanan aman yang disediakan oleh sistem operasi—seperti iOS Keychain dan Android Keystore—merupakan pilihan yang tepat, karena fasilitas tingkat sistem operasi ini dirancang khusus untuk menyimpan kredensial sensitif secara aman dan terisolasi dari aplikasi lain yang berjalan pada perangkat yang sama.


Kerentanan Keamanan JWT yang Umum


Serangan algoritma "none" memanfaatkan fakta bahwa spesifikasi JWT secara teknis mengizinkan nilai header `alg: none`, yang menandakan token tanpa tanda tangan sama sekali. Server yang logika verifikasi tokennya secara naif memercayai dan mengikuti algoritma apa pun yang tercantum dalam header token masuk—alih-alih secara mandiri menetapkan algoritma yang diharapkan dan diterima di sisi server—dapat tertipu untuk menerima token yang dibuat penyerang tanpa tanda tangan yang valid. Hal ini merupakan jenis kerentanan serius yang terdokumentasi dengan baik, di mana penyerang hanya perlu mengatur header untuk menyatakan bahwa tidak ada tanda tangan yang diperlukan. Mitigasi yang tepat sangatlah sederhana, yaitu kode verifikasi di sisi server harus selalu menentukan dan menerapkan algoritma yang diharapkan secara eksplisit, serta tidak boleh hanya mengikuti nilai algoritma yang kebetulan tercantum dalam header token itu sendiri.

Kerentanan lain yang sangat terkait dan sama seriusnya—terkadang disebut sebagai serangan algorithm confusion—menargetkan sistem yang menggunakan penandatanganan asimetris (RS256). Dalam serangan ini, logika verifikasi server dapat tertipu untuk memperlakukan kunci publik (yang secara definisi tidak bersifat rahasia dan bahkan mungkin sengaja dipublikasikan untuk keperluan verifikasi semacam ini) seolah-olah kunci tersebut adalah kunci rahasia HMAC. Karena kunci publik tersebut tidak bersifat rahasia, penyerang yang mengetahuinya dapat menggunakannya untuk memalsukan token HS256 dengan tanda tangan yang valid. Server yang rentan—karena bingung mengenai algoritma dan jenis kunci yang sebenarnya sedang diproses—akan secara keliru menerima token palsu tersebut sebagai token yang sah. Di sini pun, mitigasi yang tepat adalah memastikan kode verifikasi menerapkan algoritma spesifik yang diharapkan untuk kunci tertentu secara ketat dan eksplisit, alih-alih membiarkan keputusan krusial tersebut dipengaruhi oleh elemen apa pun di dalam token yang tidak tepercaya itu sendiri.

Kunci rahasia HMAC yang lemah atau bocor merupakan kerentanan yang lebih umum terjadi, yaitu karena penandatanganan HMAC sepenuhnya bergantung pada satu kunci rahasia bersama, kunci yang lemah, pendek, atau mudah ditebak menjadi rentan terhadap serangan brute-force yang bertujuan mengungkap nilai kunci rahasia yang sebenarnya. Jika kunci tersebut berhasil didapatkan, penyerang dapat dengan bebas memalsukan token apa pun yang sepenuhnya valid. Secret yang digunakan untuk penandatanganan JWT harus panjang, benar-benar acak, dan dikelola dengan tingkat kehati-hatian operasional serta kerahasiaan yang sama seperti kredensial bernilai tinggi lainnya—tidak boleh dimasukkan ke dalam sistem kontrol sumber, tidak boleh dikodekan secara langsung di dalam kode aplikasi, serta harus dirotasi secara berkala sebagai bagian dari postur keamanan yang matang.

Menyimpan data yang berlebihan atau sensitif di dalam payload merupakan kesalahan desain—bukan kerentanan kriptografis dalam pengertian yang ketat—namun hal ini umum terjadi dan memiliki dampak yang nyata, yaitu karena payload JWT (seperti yang telah dijelaskan sebelumnya) hanya dikodekan dan tidak dienkripsi, serta dapat dibaca sepenuhnya oleh siapa pun yang memiliki salinan token tersebut, maka informasi pribadi yang benar-benar sensitif yang ditempatkan langsung di dalam claims pada dasarnya ditransmisikan dan disimpan dalam bentuk plain text ke mana pun token tersebut berpindah atau dicatat dalam log.


Masalah Pencabutan (Revocation)


Karena nilai utama dari JWT yang bersifat stateless (tanpa status) adalah kemampuannya untuk diverifikasi secara independen oleh server mana pun hanya melalui pemeriksaan tanda tangan kriptografis—tanpa perlu merujuk pada penyimpanan terpusat yang memuat daftar token yang valid saat ini—maka secara desain, tidak ada mekanisme alami dalam model ini bagi server untuk memeriksa apakah "token spesifik ini telah dicabut secara eksplisit sejak diterbitkan?". Sebuah JWT yang ditandatangani secara sah dan belum mencapai waktu kedaluwarsanya akan terus dianggap valid sepenuhnya dan tanpa syarat oleh server verifikasi mana pun—meskipun pengguna telah keluar (log out), akun mereka telah ditangguhkan karena pelanggaran kebijakan, atau bahkan jika token tersebut kemudian diketahui telah dicuri.

Batasan ini mendorong penggunaan pola dua token (access token dan refresh token) yang dijelaskan sebelumnya, karena pola ini memungkinkan access token memiliki masa berlaku yang benar-benar singkat dan bersifat stateless (membatasi durasi risiko jika token disalahgunakan hingga maksimal beberapa menit), sekaligus memberikan kemampuan pencabutan yang nyata dan segera melalui refresh token. Berbeda dengan access token, refresh token sengaja diimplementasikan sebagai kredensial yang bersifat stateful (memiliki status) dan dilacak dalam database, khusus agar dapat dicabut secara instan dan tepat saat dibutuhkan.

Untuk situasi yang menuntut pencabutan segera terhadap access token yang sedang aktif—misalnya akun yang disusupi dan harus segera dikunci aksesnya saat itu juga, bukan menunggu beberapa menit kemudian—beberapa sistem menerapkan denylist di sisi server (terkadang masih disebut dengan istilah lama "blacklist") yang memuat pengenal token spesifik (menggunakan klaim `jti` atau JWT ID) yang telah dicabut secara eksplisit sebelum masa berlakunya habis. Sistem kemudian memeriksa setiap token yang masuk terhadap daftar ini pada setiap permintaan. Perlu disampaikan secara terus terang mengenai implikasi pola ini, yaitu memelihara dan memeriksa daftar semacam itu pada setiap permintaan justru memunculkan kembali mekanisme pencarian terpusat yang sebelumnya ingin dihilangkan oleh konsep JWT yang stateless; hal ini secara signifikan mengurangi keunggulan utama sifat stateless yang kemungkinan besar menjadi alasan awal pemilihan JWT tersebut. Tim yang menerapkan pola ini harus memahami dengan jelas bahwa mereka membuat kompromi yang disengaja dan berdasarkan informasi — lebih memilih kontrol pencabutan yang tepat daripada arsitektur tanpa status murni — daripada mendapatkan yang terbaik dari kedua pendekatan secara cuma-cuma.
Advertisement:
Jadi pada intinya, JSON Web Token (JWT) merupakan gagasan yang sangat sederhana, yaitu sekumpulan klaim yang ringkas, mandiri, dan ditandatangani secara kriptografis, yang keaslian serta integritasnya dapat diverifikasi secara independen oleh pihak tepercaya mana pun yang memegang kunci verifikasi yang tepat, tanpa perlu mengakses penyimpanan data sesi terpusat yang digunakan bersama.
Artikel Terkait: