Menggunakan kunci simetris (HMAC) untuk memvalidasi JSON Web Token (JWT) di arsitektur microservices memicu risiko keamanan horizontal yang masif. Satu layanan konsumen yang terkompromi dapat mengekstraksi shared secret tersebut dan menggunakannya untuk menerbitkan token palsu dengan hak akses arbitrer ke layanan lain. Solusi standar industri untuk mengisolasi batas kepercayaan (trust boundary) ini adalah penandatanganan asimetris (RS256/ES256) yang dipadukan dengan validasi JSON Web Key Set (JWKS) publik.

Risiko Kebocoran Shared Secret pada Sistem Terdistribusi

Pada skema simetris (HS256), entitas penerbit (Authorization Server) dan entitas verifikator (Resource Servers) memegang kunci rahasia yang identik. Konsekuensinya:

  • Blast radius maksimal: Jika satu microservice pihak ketiga atau servis non-kritis berhasil dibobol via remote code execution (RCE) atau inspeksi memori, kunci rahasia tersebut bocor untuk seluruh kluster.
  • Ketiadaan non-repudiation: Layanan otentikasi tidak dapat membuktikan secara kriptografis bahwa token bukan dibuat oleh salah satu service internal yang memegang secret tersebut.
  • Kompleksitas rotasi: Mengganti secret membutuhkan deployment serentak di semua service tanpa jeda, yang hampir selalu menimbulkan race condition atau downtime parsing token.

Analogi ideal arsitektur ini menyerupai sistem paspor fisik: instansi imigrasi pusat mencetak paspor dengan stempel segel tak tertiru (private key), sementara petugas di setiap perbatasan negara independen cukup membawa katalog spesimen cap resmi (public key) untuk memverifikasi keaslian tanpa pernah mampu menduplikasi alat stempel aslinya.

Skema Asimetris: RS256 vs ES256

Otentikasi lintas layanan modern menggunakan kunci publik-privat. Authorization Server menandatangani payload menggunakan private key, sedangkan microservice konsumen hanya perlu mengambil public key dari endpoint JWKS (biasanya diakses via /.well-known/jwks.json).

  • RS256 (RSA Signature with SHA-256): Ukuran key 2048-bit hingga 4096-bit. Kompatibilitas sangat luas di berbagai legacy runtime, namun payload token berukuran besar dan operasi verifikasi memakan CPU cycles lebih tinggi.
  • ES256 (ECDSA using P-256 and SHA-256): Menggunakan kurva eliptik. Menyediakan tingkat keamanan setara RS256-3072 bit hanya dengan ukuran key 256-bit. Sangat direkomendasikan untuk throughput tinggi dan komunikasi antar microservice berlatensi rendah.

Mitigasi Celah Kriptografis: Alg Confusion & Key Spoofing

Mengimplementasikan verifikasi berbasis remote public key membawa dua vektor serangan utama yang harus ditutup secara eksplisit di level kode:

1. Algorithm Confusion Attack

Penyerang mengubah header token dari "alg": "RS256" menjadi "alg": "HS256", lalu menandatangani token menggunakan kunci publik RS256 Auth Server yang tersedia terbuka. Jika library verifikator tidak mengunci algoritma secara kaku, library akan memperlakukan string kunci publik sebagai secret HMAC mentah, sehingga token palsu dianggap valid. Mitigasi: Wajib deklarasikan parameter algoritma yang diizinkan (whitelisting) secara statis di verifikator.

2. Key Spoofing via Header Injection (jku / jwk)

Penyerang menyisipkan field jku (JWK Set URL) atau jwk (inline public key) di header JWT yang mengarah ke server pengendali mereka. Mitigasi: Abaikan header jku atau jwk yang dikirim dari request klien. Service konsumen hanya boleh mengambil kunci dari URI JWKS internal yang sudah di-hardcode atau dikonfigurasi melalui environment variable tepercaya.

Implementasi Verifikasi JWKS dan In-Memory Caching

Mengambil JWKS via HTTP pada setiap request akan mengakibatkan denial of service (DoS) internal pada Auth Server dan menambah latensi jaringan secara signifikan. Kunci publik harus di-cache di memori dengan mekanisme rate-limiting saat cache-miss terjadi (ketika token memiliki kid baru).

Berikut implementasi minimal, aman, dan efisien menggunakan Node.js dan library standar jose:

import { createRemoteJWKSet, jwtVerify } from 'jose';

// Inisialisasi JWKS client dengan built-in caching dan request throttling
const JWKS_URI = new URL(process.env.AUTH_JWKS_URI || 'https://auth.internal.corp/.well-known/jwks.json');

// ponytail: caching memory terpusat; jika multi-instance per node butuh shared cache, gunakan Redis
const JWKS = createRemoteJWKSet(JWKS_URI, {
  cooldownDuration: 30_000, // Minimal delay 30s sebelum mencoba fetch ulang kid yang tidak dikenal (Cegah DoS)
  cacheMaxAge: 600_000,     // Cache key di memori selama 10 menit
});

export async function authenticateToken(jwtString) {
  try {
    const { payload, protectedHeader } = await jwtVerify(jwtString, JWKS, {
      issuer: 'https://auth.internal.corp',     // Klaim wajib: iss
      audience: 'order-service.internal.corp',  // Klaim wajib: aud
      algorithms: ['ES256', 'RS256'],           // Mitigasi Alg-Confusion: Kunci algoritma eksplisit
    });

    return { valid: true, identity: payload };
  } catch (err) {
    // Tangani token kedaluwarsa, signature mismatch, atau issuer salah
    return { valid: false, error: err.code || err.message };
  }
}

Catatan Validasi Klaim Wajib: Selalu evaluasi klaim iss (penjamin identitas), aud (tujuan spesifik layanan Anda), dan exp (kedaluwarsa). Layanan pembayaran tidak boleh menerima token yang diterbitkan untuk microservice inventaris, meskipun token tersebut valid secara kriptografis.

Prosedur Rotasi Key Tanpa Downtime

Untuk memutar kunci privat tanpa memutus sesi pengguna aktif atau request antarlayanan, terapkan pola Dual-Key Rollover:

  1. Generate Key Baru: Buat pasangan kunci baru (misal: kid: "auth-key-2026-v2"). Masukkan public key baru ke endpoint JWKS. Pada fase ini, JWKS mempublikasikan dua kunci publik sekaligus (kunci lama v1 dan kunci baru v2).
  2. Tunggu Propagasi Cache: Biarkan konfigurasi berjalan setidaknya sepanjang nilai cacheMaxAge pada service verifikator terlama agar cache public key terisi data v2.
  3. Alihkan Penandatanganan: Ubah konfigurasi Auth Server untuk mulai menandatangani token keluar menggunakan private key v2. Microservice konsumen langsung memvalidasi token baru karena public key v2 telah tersedia di cache lokal masing-masing.
  4. Pensiunkan Kunci Lama: Setelah seluruh token bertanda tangan v1 melewati batas kedaluwarsanya (max(token.exp)), hapus public key v1 dari endpoint JWKS.

Ringkasan Trade-Off

Validasi JWKS publik menghilangkan risiko penyebaran secret secara mutlak dan memungkinkan rotasi kredensial independen. Trade-off arsitekturalnya berada pada kompleksitas manajemen cache verifikator dan dependensi jaringan pada JWKS fetch awal saat cold-start service. Pastikan mekanisme fallback atau retrying diterapkan pada inisialisasi verifikator untuk menghindari kegagalan startup massal saat Auth Server sedang cold boot.