Skip to content

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:

  1. Pengguna diarahkan ke DUMEG Identity untuk login.
  2. Pengguna mengautentikasi diri di Keycloak.
  3. Keycloak mengembalikan Authorization Code ke Callback URL aplikasi.
  4. 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.com untuk production, atau http://localhost:8000 untuk 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_secret secara 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 ​

json
{
  "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:

  1. code_verifier: String acak kriptografis (antara 43 - 128 karakter, menggunakan karakter A-Z, a-z, 0-9, -, _, ., ~).
  2. code_challenge: Hasil hash SHA256 dari code_verifier, lalu di-encode ke format Base64-URL tanpa padding (=).

Contoh Kode Pembuatan PKCE (PHP): ​

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:

http
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
ParameterWajibDeskripsi
client_idYaID Client yang terdaftar di Keycloak.
response_typeYaSelalu bernilai code.
scopeYaMinimal openid profile email.
redirect_uriYaURL Callback tujuan (harus persis cocok dengan allowlist di Keycloak).
stateYaNilai acak unik per sesi untuk mencegah serangan CSRF.
nonceYaString acak untuk mencegah serangan replay pada ID Token.
code_challengeYaHash Base64-URL dari code_verifier.
code_challenge_methodYaWajib 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:

http
GET https://sdm.dumeg.com/auth/dumeg/callback?
  code=9fa2e411-736b-4bcf-a5ea-f77dfb119ce0.9fa2e4...
  &state=c4a9f91a27e34589
  &session_state=b891c3... HTTP/1.1

Validasi Parameter Callback: ​

  1. Periksa Parameter Error: Jika pengguna membatalkan login, Keycloak akan mengembalikan ?error=access_denied&error_description=....
  2. Validasi state: Bandingkan nilai state dari URL dengan state yang tersimpan di sesi lokal. Jika tidak cocok, hentikan proses segera karena indikasi serangan CSRF.
php
$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: ​

http
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_SESI

Contoh Menggunakan cURL: ​

bash
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: ​

json
{
  "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: ​

  1. Header Verification: Periksa algoritma pada JWT header (harus RS256, tolak none atau algoritma simetris yang tidak diharapkan).
  2. Signature Verification: Di production, verifikasi keaslian signature menggunakan Public Key dari endpoint JWKS: https://login.dumeg.com/realms/dumeg-internal/protocol/openid-connect/certs
  3. Issuer (iss): Nilai iss harus persis sama dengan: https://login.dumeg.com/realms/dumeg-internal
  4. Audience (aud): Nilai aud harus persis sama dengan client_id aplikasi Anda.
  5. Expiration (exp): Waktu saat ini harus sebelum waktu exp.
  6. Nonce Validation: Klaim nonce di payload JWT harus cocok dengan nonce yang Anda kirim pada langkah 4.1.

Contoh Payload ID Token yang Didekode: ​

json
{
  "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:

  1. Hapus sesi lokal aplikasi (invalidate session & regenerate CSRF token).
  2. Arahkan browser pengguna ke endpoint logout Keycloak agar sesi SSO di browser juga dihentikan:
http
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.1

9. Checklist Pengujian Integrasi Sebelum Production ​

Skenario PengujianHasil yang DiharapkanStatus
Login NormalPengguna 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 AmanAkun lama tidak langsung di-link otomatis; sistem mewajibkan verifikasi password lokal atau email ownership.[ ]
JIT ProvisioningPengguna baru otomatis terdaftar dengan role default terendah (least privilege).[ ]
Pembatalan LoginMenekan 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 LogoutLogout dari aplikasi membersihkan sesi lokal dan mengakhiri sesi SSO Keycloak di browser.[ ]
HTTPS EnforceTidak ada mixed-content atau redirect HTTP tanpa TLS pada production.[ ]

Langkah Selanjutnya ​

Developer Portal Single Sign-On (SSO) Ekosistem DUMEG