Belajar alur client credentials untuk komunikasi mesin-ke-mesin: mengenali kapan flow ini cocok dipakai, menyiapkan confidential client, menggunakan service account dan client roles, serta mengintegrasikannya dengan API backend tanpa kehadiran user.

Di episode 5 kalian mengenal authorization code flow yang membawa user lewat layar login Keycloak, lengkap dengan PKCE dan redirect URI. Episode 6 ini membalik perspektif: tidak ada user di balik layar sama sekali. Kalian akan belajar client credentials flow — alur OAuth 2.0 untuk komunikasi antara dua aplikasi, bukan antara aplikasi dan manusia. Inilah alur yang paling sering dipakai saat sebuah layanan backend memanggil layanan backend lain.
Client credentials adalah alur paling sederhana dari semua alur OAuth 2.0:
Analoginya: kalau authorization code flow itu seperti karyawan yang menunjuk kartu identitas saat masuk gedung, client credentials itu seperti kartu akses mesin milik robot pengantar barang — tidak peduli siapa yang mengirimnya, yang penting robotnya terautentikasi.
Alurnya ringkas, hanya dua langkah besar:
Tidak ada redirect, tidak ada authorization code, tidak ada interaksi user:
curl -X POST "https://kc.example.com/realms/my-realm/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=payment-service" \
-d "client_secret=4f9a2c8d..."Perhatikan grant_type=client_credentials sebagai penanda alur. Tanpa parameter itu Keycloak tidak tahu alur mana yang kalian pakai. Respons yang kembali berupa JSON:
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6...",
"expires_in": 300,
"token_type": "Bearer",
"scope": "email profile"
}Catatan penting: di alur ini Keycloak tidak mengembalikan refresh_token — tidak seperti alur yang melibatkan user. Karena tidak ada sesi user yang perlu dijaga, client cukup meminta token baru lagi saat token lama kedaluwarsa.
Setiap confidential client yang dibuat di Keycloak otomatis memiliki service account — user virtual yang namanya sama dengan client id. Saat kalian membuka tab Service account roles di admin console, user virtual inilah yang dipegang token.
Karena service account adalah user biasa dari sudut pandang Keycloak, kalian bisa:
Roles yang diberikan muncul di dalam access token:
{
"sub": "bf3a1c2e-...",
"preferred_username": "service-account-payment-service",
"realm_access": {
"roles": ["view-orders"]
},
"resource_access": {
"payment-service": {
"roles": ["approve-payment"]
}
}
}Di sini realm_access.roles berisi role global, sedangkan resource_access berisi client roles yang spesifik untuk layanan tujuan. Server tujuan bisa memeriksa role ini sebelum memproses request — inilah dasar kontrol akses mesin-ke-mesin di Keycloak.
Untuk memakai alur ini, client harus bertipe confidential — client yang punya rahasia. Langkahnya di admin console:
payment-service.Tip
Jalankan Keycloak lokal dengan kc.sh start-dev jika belum memilikinya, lalu buka admin console di http://localhost:8080/admin. Nama my-realm dan payment-service di episode ini adalah contoh yang dipakai konsisten sepanjang seri.
Secret bersifat rahasia. Jangan pernah menaruhnya di dalam kode frontend, repository publik, atau log. Simpan di environment variable atau secret manager seperti Vault, dan rotasi secara berkala lewat tab Credentials.
Client secret hanyalah salah satu metode. Keycloak mendukung beberapa cara client membuktikan identitasnya:
| Metode | Cara kerja | Kekuatan |
|---|---|---|
| Client secret | Secret dikirim di header Authorization atau di body form | Paling sederhana, cocok untuk internal |
| Signed JWT | Client menandatangani JWT assertion dengan key pribadinya | Tidak perlu secret di transmisi |
| mTLS | Client memakai sertifikat TLS untuk autentikasi | Paling kuat, cocok untuk perimeter ketat |
Metode dipilih lewat dropdown Client authentication di tab Credentials. Untuk mayoritas kasus internal, client secret sudah cukup; untuk integrasi lintas organisasi atau infrastruktur bersertifikat, pertimbangkan JWT atau mTLS.
Pola paling umum adalah layanan backend meminta token, lalu mengirimkannya ke API tujuan sebagai Bearer token:
TOKEN=$(curl -s -X POST "https://kc.example.com/realms/my-realm/protocol/openid-connect/token" \
-d "grant_type=client_credentials" \
-d "client_id=payment-service" \
-d "client_secret=4f9a2c8d..." | jq -r .access_token)
curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.example.com/orders/pending"Langkah kunci di sisi API tujuan: validasi signature token lewat JWKS, periksa iss, aud, dan exp, lalu cek role dari realm_access atau resource_access sebelum mengizinkan request.
Alur ini paling sering muncul di empat skenario:
Untuk job terjadwal, ingat: token punya masa berlaku terbatas (expires_in). Jangan simpan token lama di disk; minta token baru saat akan digunakan.
Di episode 6 ini kalian belajar client credentials flow: kapan memakainya, bagaimana token diminta dan dipakai, peran service account dan client roles, konfigurasi confidential client, metode autentikasi client, serta contoh integrasi API.
Inti yang harus dibawa pulang:
resource_access mengontrol apa yang boleh dilakukan service.iss, aud, exp, dan role sebelum memproses.Di episode 7 berikutnya kita masuk ke manajemen token yang lebih dalam: refresh token — bagaimana memperpanjang akses user tanpa meminta password lagi, kapan token dirotasi, dan bagaimana menonaktifkannya saat dicuri atau dihentikan.