Jelajahi evolusi autentikasi enterprise dari LDAP dan Active Directory ke sistem OAuth 2.0 dan SSO modern. Pelajari cara kerja IAM, pahami autentikasi berbasis token, dan temukan mengapa organisasi bermigrasi ke solusi identitas cloud-native.

Autentikasi dan otorisasi adalah penjaga gerbang sistem modern. Setiap kali Anda masuk ke aplikasi, identitas Anda diverifikasi (autentikasi) dan izin Anda diperiksa (otorisasi). Namun, cara ini terjadi telah berubah secara fundamental selama dua dekade terakhir.
Selama bertahun-tahun, perusahaan mengandalkan LDAP dan Active Directory—layanan direktori terpusat yang bekerja baik dalam jaringan korporat. Hari ini, organisasi beroperasi di seluruh platform cloud, perangkat mobile, dan tim terdistribusi. Model lama tidak berfungsi. Sistem modern membutuhkan sesuatu yang berbeda: Single Sign-On (SSO) yang didukung oleh OAuth 2.0 dan OpenID Connect.
Pergeseran ini bukan hanya teknis—ini adalah arsitektur. Memahami evolusi ini membantu Anda membuat keputusan yang lebih baik tentang infrastruktur identitas, postur keamanan, dan pengalaman pengguna.
LDAP (Lightweight Directory Access Protocol) revolusioner untuk zamannya. Ini menyediakan cara terpusat untuk menyimpan dan menanyakan kredensial pengguna dan informasi organisasi.
Cara kerja LDAP:
Masalahnya: LDAP mengasumsikan pengguna berada di jaringan korporat. Akses VPN canggih. Mobile? Lupakan saja. Kolaborasi lintas organisasi memerlukan pengaturan federasi yang kompleks.
Active Directory (AD) Microsoft memperluas LDAP dengan autentikasi Kerberos, kebijakan grup, dan integrasi Windows yang mendalam. Ini menjadi standar de facto untuk identitas enterprise.
Mengapa AD kuat:
Keterbatasannya: AD dirancang untuk jaringan on-premises. Adopsi cloud mengungkap kelemahannya. Mengelola identitas di AWS, Azure, dan aplikasi SaaS menjadi mimpi buruk.
Ketika organisasi pindah ke platform cloud dan mengadopsi aplikasi SaaS, model baru muncul: autentikasi stateless berbasis token. OAuth 2.0 dan OpenID Connect menjadi standar.
Mengapa pergeseran terjadi:
OAuth 2.0 adalah kerangka kerja otorisasi, bukan protokol autentikasi. Perbedaan ini penting.
Otorisasi = "Apa yang boleh Anda lakukan?" Autentikasi = "Siapa Anda?"
OAuth 2.0 menjawab pertanyaan otorisasi. Ini memungkinkan pengguna memberikan izin aplikasi untuk mengakses sumber daya mereka tanpa berbagi kata sandi.
Bayangkan Anda di restoran dan ingin membayar dengan kartu kredit:
OAuth 2.0 bekerja serupa:
┌─────────────┐
│ Pemilik │
│ Sumber │
│ Daya │
│ (Pengguna) │
└──────┬──────┘
│
│ 1. Memulai login
▼
┌─────────────────┐ ┌──────────────────┐
│ Aplikasi │◄───────►│ Server │
│ Klien │ 2,3,4 │ Otorisasi (IdP) │
└─────────────────┘ └──────────────────┘
│ │
│ 5. Token Akses │
│◄───────────────────────────┘
│
▼
┌──────────────────┐
│ Server Sumber │
│ Daya (API) │
└──────────────────┘Pemilik Sumber Daya: Pengguna yang datanya diakses Aplikasi Klien: Aplikasi Anda yang meminta akses Server Otorisasi: Penyedia identitas (IdP) yang memverifikasi identitas Server Sumber Daya: API atau layanan yang menyimpan data pengguna
Realm adalah pengelompokan logis pengguna, aplikasi, dan kebijakan. Pikirkan ini sebagai namespace untuk identitas.
Contoh: Perusahaan mungkin memiliki:
Setiap realm memiliki:
realm:
name: production
enabled: true
users:
- id: user123
username: alice@company.com
email: alice@company.com
applications:
- clientId: web-app
redirectUris:
- https://app.company.com/callback
- clientId: mobile-app
redirectUris:
- com.company.app://callback
policies:
- name: require-mfa
enabled: trueKlaim adalah pernyataan tentang pengguna. Mereka adalah pasangan kunci-nilai yang disertakan dalam token yang menggambarkan siapa pengguna dan apa yang boleh mereka lakukan.
Klaim standar:
sub (subject): Pengenal pengguna unikiss (issuer): Siapa yang mengeluarkan tokenaud (audience): Siapa token itu untukexp (expiration): Kapan token kedaluwarsaiat (issued at): Kapan token dibuatKlaim khusus:
department: "Engineering"role: "Senior Engineer"team: "Platform"permissions: ["read:logs", "write:config"]{
"sub": "user123",
"iss": "https://idp.company.com",
"aud": "web-app",
"exp": 1708108800,
"iat": 1708022400,
"email": "alice@company.com",
"department": "Engineering",
"role": "Senior Engineer",
"permissions": ["read:logs", "write:config", "deploy:staging"]
}Token adalah inti dari OAuth 2.0. Mereka adalah kredensial yang ditandatangani secara kriptografis yang membuktikan identitas dan otorisasi.
Token Akses: Token jangka pendek yang digunakan untuk mengakses API
Token Refresh: Token jangka panjang yang digunakan untuk mendapatkan token akses baru
Token ID: Berisi informasi identitas pengguna (OpenID Connect)
// 1. Pengguna masuk, menerima kode otorisasi
const authCode = "auth_code_xyz";
// 2. Tukar kode dengan token
const tokenResponse = await fetch("https://idp.company.com/token", {
method: "POST",
body: JSON.stringify({
grant_type: "authorization_code",
code: authCode,
client_id: "web-app",
client_secret: "secret_xyz",
redirect_uri: "https://app.company.com/callback"
})
});
// 3. Respons berisi token
const { access_token, refresh_token, id_token, expires_in } =
await tokenResponse.json();
// 4. Gunakan token akses untuk panggilan API
const apiResponse = await fetch("https://api.company.com/user", {
headers: {
Authorization: `Bearer ${access_token}`
}
});Kerberos sering disebutkan bersama OAuth 2.0, tetapi secara fundamental berbeda. Memahami perbedaannya membantu Anda memilih alat yang tepat.
Kerberos menggunakan sistem berbasis tiket bukan token:
Kata Sandi Pengguna
│
▼
┌──────────────────┐
│ Server Kerberos │
│ (KDC) │
└──────────────────┘
│
│ Ticket Granting Ticket (TGT)
▼
Cache Pengguna
│
├─► Minta Tiket Layanan untuk App A
│ │
│ ▼
│ ┌──────────────────┐
│ │ Server Kerberos │
│ └──────────────────┘
│ │
│ │ Tiket Layanan
│ ▼
└─► App A (Verifikasi dengan KDC)| Aspek | Kerberos | OAuth 2.0 |
|---|---|---|
| Era Desain | 1980-an (berpusat jaringan) | 2010-an (berpusat internet) |
| Asumsi Jaringan | Jaringan internal terpercaya | Internet tidak terpercaya |
| Berbagi Kredensial | Tiket (terbatas waktu) | Token (ditandatangani secara kriptografis) |
| Skalabilitas | Memerlukan ketersediaan KDC | Stateless, sangat scalable |
| Mobile/Cloud | Cocok buruk | Cocok sempurna |
| Kasus Penggunaan | Jaringan enterprise | Cloud, SaaS, API |
Tip
Kerberos masih berharga untuk lingkungan enterprise on-premises. Banyak sistem SSO modern mendukung Kerberos sebagai fallback untuk aplikasi legacy sambil menggunakan OAuth 2.0 untuk layanan baru.
Salah satu kekhawatiran terbesar selama migrasi: "Bagaimana dengan infrastruktur LDAP kami yang ada?"
Kabar baiknya: Sistem SSO modern mempertahankan kompatibilitas LDAP melalui jembatan dan konektor.
Banyak sistem SSO dapat menggunakan LDAP sebagai direktori pengguna backend:
sso:
name: company-sso
userStore:
type: ldap
connection:
url: ldap://ldap.company.com:389
baseDn: dc=company,dc=com
bindDn: cn=admin,dc=company,dc=com
userMapping:
username: uid
email: mail
displayName: cn
groups: memberOfCara kerjanya:
Untuk aplikasi yang hanya memahami LDAP, sistem SSO dapat bertindak sebagai proxy LDAP:
Aplikasi Legacy
│
│ Kueri LDAP
▼
┌──────────────────┐
│ Sistem SSO │
│ (Proxy LDAP) │
└──────────────────┘
│
│ Kueri LDAP
▼
┌──────────────────┐
│ Direktori LDAP │
└──────────────────┘Ini memungkinkan aplikasi legacy terus bekerja sambil Anda bermigrasi ke OAuth 2.0 untuk layanan baru.
OAuth 2.0 menangani otorisasi, tetapi bagaimana dengan autentikasi? Di situlah OpenID Connect (OIDC) masuk.
OIDC adalah lapisan tipis di atas OAuth 2.0 yang menambahkan autentikasi. Ini memperkenalkan token ID, yang berisi klaim tentang identitas pengguna.
// OAuth 2.0: Dapatkan token akses untuk memanggil API
const response = await fetch("https://idp.company.com/token", {
method: "POST",
body: JSON.stringify({
grant_type: "authorization_code",
code: authCode,
client_id: "web-app",
client_secret: "secret"
})
});
const { access_token } = await response.json();
// Gunakan access_token untuk memanggil API// OIDC: Dapatkan token akses DAN id_token
const response = await fetch("https://idp.company.com/token", {
method: "POST",
body: JSON.stringify({
grant_type: "authorization_code",
code: authCode,
client_id: "web-app",
client_secret: "secret",
scope: "openid profile email" // Scope OIDC
})
});
const { access_token, id_token } = await response.json();
// id_token berisi informasi identitas pengguna
// access_token digunakan untuk memanggil APIPertama, daftarkan aplikasi Anda dengan penyedia SSO:
application:
name: my-web-app
clientId: my-web-app-prod
clientSecret: ${OAUTH_CLIENT_SECRET}
redirectUris:
- https://app.company.com/auth/callback
- https://app.company.com/auth/callback/mobile
allowedScopes:
- openid
- profile
- email
- offline_access
tokenEndpointAuthMethod: client_secret_basic
accessTokenLifespan: 3600
refreshTokenLifespan: 604800export async function fetchUserData() {
const accessToken = sessionStorage.getItem('access_token');
const response = await fetch('https://api.company.com/user', {
headers: {
Authorization: `Bearer ${accessToken}`
}
});
if (response.status === 401) {
// Token kedaluwarsa, segarkan
await refreshAccessToken();
return fetchUserData(); // Coba lagi
}
return response.json();
}
async function refreshAccessToken() {
const response = await fetch('/api/auth/refresh', {
method: 'POST'
});
const { access_token } = await response.json();
sessionStorage.setItem('access_token', access_token);
}Masalahnya:
// Rentan terhadap serangan XSS
localStorage.setItem('access_token', token);Mengapa berbahaya: JavaScript apa pun di halaman (termasuk skrip berbahaya dari kerentanan XSS) dapat membaca localStorage.
Solusinya:
// Simpan di cookie httpOnly (hanya server-side)
// Server menetapkan: Set-Cookie: access_token=...; HttpOnly; Secure; SameSite=StrictMasalahnya:
// Mempercayai token tanpa verifikasi
const user = JSON.parse(atob(idToken.split('.')[1]));Mengapa berbahaya: Siapa pun dapat membuat JWT palsu. Anda harus memverifikasi tanda tangan.
Solusinya:
import jwt from 'jsonwebtoken';
const publicKey = await fetchIdpPublicKey();
const decoded = jwt.verify(idToken, publicKey, {
algorithms: ['RS256'],
issuer: 'https://idp.company.com',
audience: 'my-web-app-prod'
});Masalahnya:
// Menggunakan token kedaluwarsa
const token = sessionStorage.getItem('access_token');
// Tidak ada pemeriksaan kedaluwarsaSolusinya:
function isTokenExpired(token: string): boolean {
const decoded = jwt.decode(token) as any;
return decoded.exp * 1000 < Date.now();
}
if (isTokenExpired(accessToken)) {
await refreshAccessToken();
}Masalahnya:
// Alur kode otorisasi tanpa PKCE
const params = new URLSearchParams({
client_id: 'my-app',
redirect_uri: 'https://app.company.com/callback',
response_type: 'code'
// Hilang code_challenge
});Mengapa berbahaya: Tanpa PKCE, kode otorisasi dapat disadap dan digunakan oleh penyerang.
Solusinya:
// Selalu gunakan PKCE untuk SPA
const codeChallenge = generateCodeChallenge(codeVerifier);
const params = new URLSearchParams({
client_id: 'my-app',
redirect_uri: 'https://app.company.com/callback',
response_type: 'code',
code_challenge: codeChallenge,
code_challenge_method: 'S256'
});PKCE (Proof Key for Code Exchange) melindungi terhadap serangan intersepsi kode otorisasi.
function generateCodeChallenge(codeVerifier: string): string {
const hash = crypto.createHash('sha256').update(codeVerifier).digest();
return base64url(hash);
}
// Selalu sertakan dalam permintaan otorisasi
const codeChallenge = generateCodeChallenge(codeVerifier);Token refresh harus dirotasi pada setiap penggunaan untuk membatasi paparan:
async function refreshAccessToken(refreshToken: string) {
const response = await fetch('https://idp.company.com/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: 'my-app',
client_secret: process.env.OAUTH_CLIENT_SECRET
})
});
const { access_token, refresh_token: newRefreshToken } =
await response.json();
// Simpan token refresh baru (yang lama tidak valid)
await storeRefreshToken(newRefreshToken);
return access_token;
}Logout harus membatalkan token di klien dan server:
async function logout() {
// Hapus token klien
sessionStorage.removeItem('access_token');
// Batalkan token refresh di server
await fetch('/api/auth/logout', {
method: 'POST'
});
// Arahkan ke endpoint logout SSO
window.location.href = 'https://idp.company.com/logout?' +
new URLSearchParams({
post_logout_redirect_uri: 'https://app.company.com'
});
}monitoring:
alerts:
- name: multiple-failed-logins
condition: failed_login_attempts > 5 in 5m
action: lock_account
- name: token-reuse-detected
condition: same_refresh_token_used_twice
action: invalidate_all_tokens
- name: unusual-location
condition: login_from_new_country
action: require_mfaPertahankan masa pakai token akses pendek (15-60 menit) untuk membatasi kerusakan jika dikompromikan:
tokenPolicy:
accessToken:
lifetime: 900 # 15 menit
refreshable: false
refreshToken:
lifetime: 604800 # 7 hari
rotateOnUse: trueUntuk sistem dengan persyaratan keamanan ekstrem (transaksi keuangan, kesehatan), pertimbangkan lapisan tambahan:
OAuth 2.0 masih sesuai, tetapi dengan kebijakan yang lebih ketat.
Jika Anda memiliki sistem yang hanya mendukung LDAP atau Kerberos dan tidak dapat diperbarui:
Aplikasi yang harus bekerja tanpa konektivitas jaringan:
Untuk autentikasi layanan-ke-layanan, alur kredensial klien OAuth 2.0 sesuai, tetapi pertimbangkan:
┌─────────────────────────────────────────┐
│ Sistem SSO Pusat │
├─────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Realm │ │ Realm │ │
│ │ Produksi │ │ Staging │ │
│ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Realm │ │ Realm │ │
│ │ Internal │ │ Mitra │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────┘
│ │
┌────┴──────────────┴────┐
│ │
▼ ▼
┌─────────────┐ ┌──────────────┐
│ Aplikasi │ │ Aplikasi │
│ Web │ │ Mobile │
└─────────────┘ └──────────────┘┌──────────────────────┐ ┌──────────────────────┐
│ SSO Perusahaan A │ │ SSO Perusahaan B │
│ (IdP) │ │ (IdP) │
└──────────────────────┘ └──────────────────────┘
│ │
└─────────────┬───────────────┘
│
┌──────▼──────┐
│ Broker │
│ Federasi │
└──────┬──────┘
│
┌─────────────┴─────────────┐
│ │
▼ ▼
┌─────────┐ ┌──────────┐
│ Aplikasi│ │ Aplikasi │
│ A │ │ B │
└─────────┘ └──────────┘migration:
phase1:
duration: 2 weeks
tasks:
- audit_applications
- assess_complexity
- plan_rollout
phase2:
duration: 4 weeks
pilot_apps:
- internal-wiki
- status-page
phase3:
duration: 10 weeks
batches:
- batch1: [jira, confluence, slack]
- batch2: [github, gitlab, npm-registry]
- batch3: [custom-apps]
phase4:
duration: ongoing
tasks:
- monitor_stability
- optimize_performance
- decommission_ldapPergeseran dari LDAP dan Active Directory ke OAuth 2.0 dan SSO mewakili lebih dari sekadar peningkatan teknologi—ini adalah evolusi arsitektur yang didorong oleh cara kita bekerja hari ini.
Poin-poin kunci:
Mulai dengan program pilot, pelajari dari penggunaan dunia nyata, dan migrasikan secara bertahap. Investasi dalam infrastruktur identitas modern memberikan dividen dalam keamanan, skalabilitas, dan pengalaman pengguna.
Langkah berikutnya Anda: Evaluasi solusi SSO untuk kebutuhan spesifik organisasi Anda, mempertimbangkan faktor-faktor seperti infrastruktur yang ada, persyaratan kepatuhan, dan keahlian tim.