JSON Web Token (JWT) adalah standar terbuka untuk merepresentasikan klaim (claims) secara aman antara dua pihak dalam bentuk JSON yang ditandatangani secara digital, menjadi metode autentikasi paling umum dipakai pada REST API modern karena sifatnya yang stateless dan tidak membutuhkan session di sisi server.
JWT terdiri dari tiga bagian yang dipisahkan titik: header (algoritma signing), payload (data klaim seperti user id dan role), dan signature (tanda tangan digital yang memverifikasi token tidak diubah), semuanya di-encode dengan Base64 dan digabung menjadi satu string token.
Artikel ini membahas cara mengonfigurasi autentikasi JWT di ASP.NET Core Web API, mulai dari menghasilkan token saat login berhasil, memvalidasi token pada setiap request, hingga melindungi endpoint tertentu agar hanya bisa diakses pengguna yang sudah terautentikasi.
Menghasilkan JWT Saat Login Berhasil
Token dihasilkan dengan claims, signing key, dan masa berlaku
Mengonfigurasi Validasi JWT di Middleware
Konfigurasi validasi memastikan token asli dan belum kedaluwarsa
Melindungi Endpoint dengan Atribut Authorize
Atribut Authorize memeriksa token sebelum action dijalankan
Mengirim Token pada Request Berikutnya
Token dikirim lewat header Authorization dengan skema Bearer
Refresh Token: Mengatasi Access Token JWT yang Masa Berlakunya Pendek
Rotasi refresh token: token lama dicabut setiap kali dipakai untuk refresh
Access token JWT sengaja dibuat berumur pendek, biasanya 15 hingga 60 menit, agar dampak kebocoran token tetap terbatas waktu. Namun masa berlaku sependek itu tidak praktis jika user harus login ulang setiap kali token kedaluwarsa, sehingga pola refresh token dipakai: sebuah token kedua yang masa berlakunya jauh lebih panjang (misalnya 7 hari) dan disimpan di database, dipakai khusus untuk meminta access token baru tanpa perlu memasukkan kredensial ulang.
Praktik keamanan yang penting pada implementasi refresh token adalah token rotation, yaitu setiap kali refresh token dipakai untuk mendapatkan access token baru, refresh token lama langsung dicabut (IsRevoked = true) dan refresh token baru diterbitkan. Dengan pola ini, jika refresh token yang sudah dicabut tiba-tiba dipakai lagi, sistem bisa mendeteksi indikasi pencurian token dan mencabut seluruh sesi milik user tersebut sebagai langkah pengamanan.
Refresh token sebaiknya disimpan di database (bukan hanya di JWT itu sendiri) justru karena JWT access token bersifat stateless dan tidak bisa dicabut sebelum masa berlakunya habis; dengan menjadikan refresh token sebagai record di database yang punya status IsRevoked, tim bisa memaksa logout seluruh sesi seorang user kapan saja, sesuatu yang tidak mungkin dilakukan hanya dengan mengandalkan access token JWT yang murni self-contained.
Claims-Based Identity: Menyimpan dan Membaca Data User dari Token
ClaimsPrincipal (User) di controller terisi otomatis dari payload JWT yang tervalidasi
Setiap JWT yang berhasil divalidasi oleh middleware autentikasi secara otomatis diubah menjadi objek ClaimsPrincipal yang tersedia lewat properti User di dalam controller, berisi seluruh claim yang disisipkan saat token diterbitkan. Pola ini memungkinkan informasi dasar tentang user yang sedang login, seperti id, email, atau departemen, diambil langsung dari token tanpa perlu melakukan query tambahan ke database pada setiap request yang membutuhkannya. Pendekatan ini mengurangi beban database secara signifikan pada endpoint yang sering diakses dan hanya membutuhkan identitas dasar user.
Claim kustom seperti "Departemen" atau "JobLevel" pada contoh di atas ditambahkan secara manual saat proses pembuatan token di AuthService, dan nilainya tidak akan berubah sampai user tersebut login ulang dan mendapatkan token baru. Konsekuensinya, data yang disimpan sebagai claim sebaiknya berupa informasi yang jarang berubah dalam rentang waktu masa berlaku token, karena perubahan departemen seorang user tidak akan langsung tercermin pada token lama yang masih aktif. Informasi yang sering berubah seperti saldo atau status langganan sebaiknya tetap diambil dari database, bukan disimpan sebagai claim pada token.
Untuk mempermudah pembacaan claim yang berulang di banyak controller, praktik yang baik adalah membuat extension method pada ClaimsPrincipal, misalnya User.GetUserId() atau User.GetDepartemen(), sehingga logika pengambilan claim terpusat di satu tempat dan tidak perlu mengetik string literal nama claim secara berulang di setiap endpoint yang membutuhkannya, sekaligus mengurangi risiko salah ketik nama claim antar file. Extension method ini juga memudahkan perubahan nama claim di masa depan karena cukup diubah di satu tempat saja.
Cookie Authentication vs JWT: Memilih Sesuai Jenis Klien
Cookie authentication mengandalkan browser untuk menyimpan dan mengirim cookie secara otomatis pada setiap request yang dikirim ke server, sehingga sangat cocok untuk aplikasi web tradisional seperti Razor Pages atau MVC yang seluruhnya dirender di sisi server. Proses logout dan invalidasi sesi juga menjadi lebih sederhana karena server bisa langsung menghapus cookie atau menandainya sebagai tidak valid tanpa perlu mekanisme tambahan di sisi klien.
JWT jauh lebih cocok dipakai untuk API yang dikonsumsi oleh klien non-browser seperti aplikasi mobile atau layanan lain yang berkomunikasi langsung lewat HTTP, karena token dikirim secara eksplisit lewat header Authorization dan tidak bergantung pada mekanisme cookie bawaan browser. Memilih salah satu dari keduanya sebaiknya mengikuti jenis klien utama yang dilayani aplikasi, bukan dipaksakan memakai JWT untuk aplikasi web yang sebenarnya cukup terlayani dengan sesi cookie biasa.
Kesalahan Umum yang Sering Terjadi
Menyimpan Secret Key JWT Langsung di Kode Sumber
Menuliskan secret key untuk signing JWT langsung di dalam kode yang ter-commit ke version control adalah risiko keamanan besar; secret key sebaiknya disimpan di User Secrets untuk development dan secret manager atau environment variable untuk production.
Memberi Masa Berlaku Token yang Terlalu Lama
Token dengan masa berlaku terlalu panjang meningkatkan risiko jika token tersebut bocor atau dicuri, karena token JWT yang sudah diterbitkan tidak bisa langsung dibatalkan tanpa mekanisme tambahan seperti token blacklist atau refresh token.
Menyimpan Data Sensitif di Payload JWT
Payload JWT hanya di-encode dengan Base64, bukan dienkripsi, sehingga siapa pun yang memiliki token bisa membaca isi payload-nya; data sensitif seperti password tidak boleh pernah dimasukkan ke dalam klaim JWT.
Kapan Pendekatan Ini Tidak Cocok Dipakai
JWT memberikan autentikasi yang stateless dan skalabel karena server tidak perlu menyimpan session, sangat cocok untuk arsitektur microservices dan API yang diakses dari berbagai jenis client.
Namun sifat stateless ini juga menjadi kekurangan karena token yang sudah diterbitkan sulit dibatalkan sebelum masa berlakunya habis, sehingga aplikasi yang butuh kemampuan logout paksa atau pencabutan akses instan perlu menambahkan mekanisme tambahan seperti refresh token dengan daftar token yang dicabut.
Ringkasan
Autentikasi JWT menjadi standar de facto untuk REST API modern berkat sifatnya yang stateless dan mudah diintegrasikan lintas platform. Pahami cara kerja signing dan validasi token, lindungi endpoint dengan atribut Authorize, dan selalu jaga keamanan secret key yang dipakai untuk menandatangani token tersebut.
Seri Belajar .NET Core:
← Sebelumnya: Repository Pattern di ASP.NET Core
→ Selanjutnya: Authorization dan Role Based Access Control (segera terbit)