Developer Quickstart
Panduan ini berisi langkah-langkah teknis untuk mengintegrasikan aplikasi web Anda dengan layanan DUMEG Identity menggunakan protokol OpenID Connect (OIDC) dan OAuth 2.0 Authorization Code Flow dengan PKCE (Proof Key for Code Exchange).
Catatan Implementasi
Potongan kode dan alur yang dijelaskan dalam quickstart ini merupakan implementasi referensi dasar. Sesuaikan penanganan sesi, database, dan manajemen token dengan kebijakan teknis aplikasi Anda sebelum diterapkan di lingkungan produksi.
1. Konsep DUMEG Identity
DUMEG Identity bertindak sebagai OpenID Provider (OP) berbasis Keycloak. Aplikasi Anda bertindak sebagai Relying Party (RP) atau OIDC Client.
Pertukaran identitas dilakukan secara terstandarisasi:
- Pengguna diarahkan ke DUMEG Identity untuk login.
- Pengguna mengautentikasi diri di Keycloak.
- Keycloak mengembalikan Authorization Code ke Callback URL aplikasi.
- Aplikasi menukarkan kode tersebut langsung ke Keycloak untuk memperoleh ID Token (klaim profil) dan Access Token.
2. Persyaratan Integrasi Aplikasi
Sebelum memulai pengkodean di aplikasi Anda, pastikan telah memenuhi persyaratan berikut:
- [x] Memiliki nama aplikasi dan domain resmi (misal:
https://app.dumeg.comuntuk production, atauhttp://localhost:8000untuk development lokal). - [x] Menyediakan Callback URL / Redirect URI spesifik (misal:
https://app.dumeg.com/auth/dumeg/callback). - [x] Menyediakan Post-Logout Redirect URI (misal:
https://app.dumeg.com/login). - [x] Menggunakan protokol HTTPS untuk lingkungan staging dan production.
- [x] Mendapatkan kredensial client dari tim infrastruktur DUMEG Identity.
3. Pendaftaran dan Konfigurasi OIDC Client
Untuk mendaftarkan aplikasi Anda di realm dumeg-internal, ajukan permintaan konfigurasi client dengan menyertakan rincian berikut:
Jenis Client (Client Type)
- Confidential Client (Direkomendasikan untuk Web Apps dengan Backend): Aplikasi berbasis server (Laravel, NodeJS, Django, Go) yang mampu menyimpan
client_secretsecara aman tanpa bisa dilihat oleh browser pengguna. - Public Client: Aplikasi frontend murni (SPA tanpa backend atau mobile app) yang tidak memiliki server rahasia. Wajib mengaktifkan PKCE S256.
Contoh Konfigurasi Client di Keycloak
{
"clientId": "portal-sdm-dumeg",
"name": "Portal SDM DUMEG",
"enabled": true,
"protocol": "openid-connect",
"publicClient": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"redirectUris": [
"https://sdm.dumeg.com/auth/dumeg/callback",
"http://localhost:8000/auth/dumeg/callback"
],
"webOrigins": [
"https://sdm.dumeg.com",
"http://localhost:8000"
],
"attributes": {
"pkce.code.challenge.method": "S256",
"post.logout.redirect.uris": "https://sdm.dumeg.com/login##http://localhost:8000/login"
}
}4. Authorization Code Flow dengan PKCE S256
PKCE (RFC 7636) mencegah serangan Authorization Code Interception. Alur ini wajib diterapkan pada semua client.
Langkah 4.1: Pembuatan Code Verifier & Code Challenge
Aplikasi Anda membuat dua nilai acak sebelum memulai redirect:
code_verifier: String acak kriptografis (antara 43 - 128 karakter, menggunakan karakterA-Z,a-z,0-9,-,_,.,~).code_challenge: Hasil hash SHA256 daricode_verifier, lalu di-encode ke format Base64-URL tanpa padding (=).
Contoh Kode Pembuatan PKCE (PHP):
// 1. Buat code_verifier
$randomBytes = random_bytes(32);
$codeVerifier = rtrim(strtr(base64_encode($randomBytes), '+/', '-_'), '=');
// 2. Buat code_challenge menggunakan SHA-256
$hash = hash('sha256', $codeVerifier, true);
$codeChallenge = rtrim(strtr(base64_encode($hash), '+/', '-_'), '=');
// 3. Buat state dan nonce unik untuk perlindungan CSRF & Replay
$state = bin2hex(random_bytes(16));
$nonce = bin2hex(random_bytes(16));
// Simpan di sesi lokal aplikasi
session([
'oidc_code_verifier' => $codeVerifier,
'oidc_state' => $state,
'oidc_nonce' => $nonce,
]);Langkah 4.2: Redirect Pengguna ke Authorization Endpoint
Susun URL otorisasi Keycloak dan arahkan browser pengguna:
GET https://login.dumeg.com/realms/dumeg-internal/protocol/openid-connect/auth?
client_id=portal-sdm-dumeg
&response_type=code
&scope=openid%20profile%20email
&redirect_uri=https%3A%2F%2Fsdm.dumeg.com%2Fauth%2Fdumeg%2Fcallback
&state=c4a9f91a27e34589
&nonce=87d891bca762411e
&code_challenge=E9Melhoa2OwvFrGMTJguCH5...
&code_challenge_method=S256 HTTP/1.1
Host: login.dumeg.com| Parameter | Wajib | Deskripsi |
|---|---|---|
client_id | Ya | ID Client yang terdaftar di Keycloak. |
response_type | Ya | Selalu bernilai code. |
scope | Ya | Minimal openid profile email. |
redirect_uri | Ya | URL Callback tujuan (harus persis cocok dengan allowlist di Keycloak). |
state | Ya | Nilai acak unik per sesi untuk mencegah serangan CSRF. |
nonce | Ya | String acak untuk mencegah serangan replay pada ID Token. |
code_challenge | Ya | Hash Base64-URL dari code_verifier. |
code_challenge_method | Ya | Wajib bernilai S256. |
5. Menangani Callback (Redirect URI)
Setelah pengguna berhasil login di Keycloak, Keycloak akan me-redirect browser kembali ke redirect_uri aplikasi Anda dengan membawa parameter query:
GET https://sdm.dumeg.com/auth/dumeg/callback?
code=9fa2e411-736b-4bcf-a5ea-f77dfb119ce0.9fa2e4...
&state=c4a9f91a27e34589
&session_state=b891c3... HTTP/1.1Validasi Parameter Callback:
- Periksa Parameter Error: Jika pengguna membatalkan login, Keycloak akan mengembalikan
?error=access_denied&error_description=.... - Validasi
state: Bandingkan nilaistatedari URL denganstateyang tersimpan di sesi lokal. Jika tidak cocok, hentikan proses segera karena indikasi serangan CSRF.
$returnedState = $request->query('state');
$savedState = session()->pull('oidc_state');
if (!$savedState || !hash_equals($savedState, $returnedState)) {
abort(403, 'Validasi state OIDC gagal. Permintaan dibatalkan.');
}
$authorizationCode = $request->query('code');6. Pertukaran Authorization Code Menjadi Token
Aplikasi backend mengirim HTTP POST langsung (back-channel) ke endpoint token Keycloak. Browser pengguna tidak boleh melakukan request ini jika aplikasi memiliki backend rahasia.
Permintaan HTTP POST:
POST /realms/dumeg-internal/protocol/openid-connect/token HTTP/1.1
Host: login.dumeg.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&client_id=portal-sdm-dumeg
&client_secret=RAHASIA_CLIENT_ANDA
&code=9fa2e411-736b-4bcf-a5ea-f77dfb119ce0.9fa2e4...
&redirect_uri=https%3A%2F%2Fsdm.dumeg.com%2Fauth%2Fdumeg%2Fcallback
&code_verifier=43_CHARACTERS_VERIFIER_STRING_DARI_SESIContoh Menggunakan cURL:
curl -X POST "https://login.dumeg.com/realms/dumeg-internal/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "client_id=portal-sdm-dumeg" \
-d "client_secret=RAHASIA_CLIENT_ANDA" \
-d "code=AUTHORIZATION_CODE_DARI_CALLBACK" \
-d "redirect_uri=https://sdm.dumeg.com/auth/dumeg/callback" \
-d "code_verifier=CODE_VERIFIER_ASLI"Respons Token dari Keycloak:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiw...",
"expires_in": 300,
"refresh_expires_in": 1800,
"refresh_token": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCIs...",
"token_type": "Bearer",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiw...",
"not-before-policy": 0,
"session_state": "b891c3da-d30f-4889-a2e5-47f9ba51897c",
"scope": "openid profile email"
}7. Validasi ID Token (JSON Web Token)
ID Token adalah JWT bertanda tangan digital (biasanya algoritma RS256). Token ini berisi informasi identitas pengguna.
Checklist Validasi Token Wajib:
- Header Verification: Periksa algoritma pada JWT header (harus
RS256, tolaknoneatau algoritma simetris yang tidak diharapkan). - Signature Verification: Di production, verifikasi keaslian signature menggunakan Public Key dari endpoint JWKS:
https://login.dumeg.com/realms/dumeg-internal/protocol/openid-connect/certs - Issuer (
iss): Nilaiissharus persis sama dengan:https://login.dumeg.com/realms/dumeg-internal - Audience (
aud): Nilaiaudharus persis sama denganclient_idaplikasi Anda. - Expiration (
exp): Waktu saat ini harus sebelum waktuexp. - Nonce Validation: Klaim
noncedi payload JWT harus cocok dengannonceyang Anda kirim pada langkah 4.1.
Contoh Payload ID Token yang Didekode:
{
"exp": 1729765200,
"iat": 1729764900,
"auth_time": 1729764900,
"jti": "5a415a77-3e1b-410a-8bf3-d7318ff24f81",
"iss": "https://login.dumeg.com/realms/dumeg-internal",
"aud": "portal-sdm-dumeg",
"sub": "48b6c45f-d893-4a18-8742-fa3f2a8901cb",
"typ": "ID",
"azp": "portal-sdm-dumeg",
"nonce": "87d891bca762411e",
"session_state": "b891c3da-d30f-4889-a2e5-47f9ba51897c",
"preferred_username": "budi.santoso",
"email": "budi.santoso@dumeg.com",
"email_verified": true,
"name": "Budi Santoso",
"given_name": "Budi",
"family_name": "Santoso"
}Identitas Unik Pengguna
Gunakan klaim sub (Subject Identifier UUID) sebagai identifier permanen pengguna dari Keycloak, bukan username atau email. Email atau username dapat berubah di masa depan, tetapi sub bersifat kekal.
8. Pengelolaan Sesi dan Logout
Sesi Aplikasi Lokal
Setelah token divalidasi dan kepemilikan akun terverifikasi, buat sesi login lokal di aplikasi Anda dan regenerasi session ID. Simpan id_token di sesi backend jika aplikasi mendukung Single Logout.
Single Logout (RP-Initiated Logout)
Ketika pengguna mengklik tombol Logout di aplikasi Anda:
- Hapus sesi lokal aplikasi (invalidate session & regenerate CSRF token).
- Arahkan browser pengguna ke endpoint logout Keycloak agar sesi SSO di browser juga dihentikan:
GET https://login.dumeg.com/realms/dumeg-internal/protocol/openid-connect/logout?
id_token_hint=ID_TOKEN_PENGGUNA
&post_logout_redirect_uri=https%3A%2F%2Fsdm.dumeg.com%2Flogin HTTP/1.19. Checklist Pengujian Integrasi Sebelum Production
| Skenario Pengujian | Hasil yang Diharapkan | Status |
|---|---|---|
| Login Normal | Pengguna diarahkan ke Keycloak, login sukses, kembali ke app dalam kondisi terotentikasi. | [ ] |
| Proteksi CSRF (State) | Jika parameter state pada callback diubah manual, aplikasi menolak request dengan status 403. | [ ] |
| Proteksi PKCE (Verifier) | Jika code_verifier sengaja disalahkan pada token exchange, Keycloak menolak request (HTTP 400). | [ ] |
| Account Linking Aman | Akun lama tidak langsung di-link otomatis; sistem mewajibkan verifikasi password lokal atau email ownership. | [ ] |
| JIT Provisioning | Pengguna baru otomatis terdaftar dengan role default terendah (least privilege). | [ ] |
| Pembatalan Login | Menekan tombol "Cancel" di Keycloak mengembalikan pengguna ke login screen aplikasi dengan pesan ramah. | [ ] |
| Penyegaran Token (Refresh) | Token dapat diperbarui menggunakan refresh_token tanpa meminta pengguna login ulang. | [ ] |
| RP-Initiated Logout | Logout dari aplikasi membersihkan sesi lokal dan mengakhiri sesi SSO Keycloak di browser. | [ ] |
| HTTPS Enforce | Tidak ada mixed-content atau redirect HTTP tanpa TLS pada production. | [ ] |
Langkah Selanjutnya
- Terapkan integrasi menggunakan framework Anda:
- Pastikan checklist keamanan terpenuhi di Panduan Standar Keamanan.