Portal Integrasi SSO Kunci
Single Sign-On (SSO) Kunci menggunakan protokol standar industri OAuth 2.0 dengan PKCE (Proof Key for Code Exchange) S256. Panduan ini menjelaskan bagaimana cara mengintegrasikan otentikasi portal pusat dengan sistem sekolah lokal secara aman.
Pendahuluan & Prasyarat
Sebelum memulai pengembangan integrasi, pastikan Anda telah mendaftarkan aplikasi sekolah Anda di portal pusat dan mendapatkan kredensial berikut:
| Kunci Kredensial | Tipe | Deskripsi / Peran |
|---|---|---|
| client_id | String | Pengidentifikasi publik unik untuk aplikasi sekolah klien Anda. Dikirim secara terbuka saat inisiasi otorisasi. |
| client_secret | String | Kunci rahasia klien. Wajib dijaga kerahasiaannya di server backend Anda. Digunakan untuk menukar code dan verifikasi webhook. |
| redirect_uri | URL | URL callback yang diizinkan untuk menerima kode otorisasi dari portal. Wajib didaftarkan persis di dashboard central. |
client_secret pada kode frontend aplikasi Anda (seperti SPA React/Vue atau aplikasi Mobile). Semua operasi penukaran token wajib diproses di server backend (backend-to-backend).client_id dan client_secret akan dikirim melalui email resmi dari kunci.co.id.1. Desain & Tampilan Layar Otorisasi (Consent UI)
Layar otorisasi (consent screen) dirancang menggunakan layout terpisah (split-screen) bergaya modern dark mode. Bagian kiri memuat branding identitas Kunci, sementara bagian kanan menyajikan permintaan izin akses bagi aplikasi sekolah klien.
+-------------------------------------------------------------------------+ | | | [ LOGO KUNCI ] [ SHIELD CHECK ICON ] | | Otorisasi Aplikasi | | Bersama Kunci Transformasi Digital | | menyediakan layanan terbaik untuk Aplikasi Demo SMK meminta izin | | edukasi dan pendidikan. akses ke akun Kunci Anda. | | | | Izin yang diminta: | | (v) Melihat profil Anda | | (Nama, ID, Foto Profil) | | (v) Melihat alamat email Anda | | | | [ SETUJU ] | | [ BATAL ] | | | +-------------------------------------------------------------------------+
2. Aliran Otentikasi (OAuth 2.0 PKCE Flow)
PKCE (Proof Key for Code Exchange) menggantikan penggunaan static secret pada perangkat klien (seperti mobile app atau single-page app) dan memperkuat pertukaran kode otorisasi pada server klien:
[ Klien (Browser/Server) ] [ Portal Pusat (Kunci) ]
| |
(1) Buat code_verifier & challenge |
(2) Redirect ke Authorize Page -------------------> |
| | (3) Login & Setuju Izin
| <------------------ (4) Redirect + code |
(5) Kirim code & code_verifier |
ke Server Lokal Klien |
| |
(6) Server Klien: POST /sso/exchange -------------> |
(Membawa client_secret, code, verifier) | (7) Validasi &
| | Bandingkan Hash
| <----------------- (8) User Profile JSON |
v v
Inisiasi Login Klien
Pengguna memilih login SSO di website sekolah. Website sekolah membuat random string code_verifier & hashing S256 code_challenge.
Pengalihan ke Portal Pusat
Pengguna diarahkan ke halaman otorisasi portal pusat membawa parameter client ID, redirect URI, scope, state, dan challenge.
Otorisasi Akun Sekolah & Consent
Jika belum masuk, pengguna memilih sekolah dan masuk dengan kredensial sekolah lokal mereka. Jika session sudah aktif, pengguna langsung menyetujui lingkup izin.
Pengembalian Code Otorisasi
Portal mengalihkan browser kembali ke redirect URI website sekolah dengan menyertakan parameter code dan state asal.
Pertukaran Kunci & Profil
Server sekolah melakukan request backend-to-backend untuk menukar code dan code_verifier asli dengan profil data pusat melalui /sso/exchange.
3. Integrasi Klien (Developer Guide)
A. Panduan Pembuatan PKCE S256
code_verifier adalah random string (minimal 43 karakter, maksimal 128 karakter) menggunakan karakter [A-Z], [a-z], [0-9], dan tanda -, ., _, ~.
// 1. Buat code_verifier
$codeVerifier = bin2hex(random_bytes(64));
// 2. Buat code_challenge (S256)
$hash = hash('sha256', $codeVerifier, true);
$codeChallenge = rtrim(strtr(base64_encode($hash), '+/', '-_'), '=');B. Langkah 1: Pengalihan Otorisasi (Authorize Redirect)
Arahkan browser pengguna ke halaman authorize dengan parameter-parameter URL berikut. Gunakan spasi (atau url-encoded %20) untuk memisahkan scope:
| Parameter | Status | Keterangan |
|---|---|---|
client_id | Wajib | ID Klien yang Anda dapatkan dari portal pusat. |
redirect_uri | Wajib | URL callback untuk menerima output code. Harus persis dengan yang didaftarkan. |
response_type | Wajib | Isi dengan string literal code. |
scope | Opsional | Informasi yang diminta, dipisahkan oleh spasi (contoh: profile email). |
code_challenge | Wajib | String challenge hasil SHA256 base64url dari code_verifier Anda. |
code_challenge_method | Wajib | Metode hashing. Harus bernilai S256. |
state | Opsional | Random string unik untuk mencegah CSRF attack. Server Anda wajib memverifikasi nilai ini pada callback. |
https://kunci.co.id/oauth/authorize?
client_id=demosmk-client-id
&redirect_uri=http://demosmk.sekolah.kunci.test/oauth/callback
&response_type=code
&scope=profile email
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWBuGJSstw-cM
&code_challenge_method=S256
&state=xyzSecretStateC. Langkah 2: Tukar Token & Profil (Token Exchange)
Setelah redirect callback selesai, server backend sekolah Anda menukar code dari browser dengan payload JSON POST ke API pusat:
| Parameter Body | Tipe | Keterangan |
|---|---|---|
client_id | String | ID Klien yang Anda miliki. |
client_secret | String | Rahasia klien aplikasi Anda. Hanya dikirim dari server-to-server. |
code | String | Kode otorisasi yang didapatkan dari query params redirect callback. |
code_verifier | String | Random string verifier asli yang digunakan untuk menghasilkan challenge di Langkah 1. |
redirect_uri | String | URI pengalihan asli. Harus sama persis dengan Langkah 1. |
{
"client_id": "demosmk-client-id",
"client_secret": "demosmk-client-secret",
"code": "AUTHORIZATION_CODE_RECEIVED",
"code_verifier": "ORIGINAL_RANDOM_CODE_VERIFIER",
"redirect_uri": "http://demosmk.sekolah.kunci.test/oauth/callback"
}{
"status": "success",
"user": {
"id": "central-user-ulid",
"name": "Ridwan Gunawan",
"email": "ridwan@sekolah.sch.id",
"display_photo_url": "https://kunci.co.id/storage/avatars/ridwan.png",
"roles": ["staff", "teacher"]
}
}E. Endpoint Tambahan: Memuat Daftar Sekolah
Gunakan API ini untuk memuat daftar sekolah aktif beserta URL aplikasinya guna ditampilkan pada halaman pemilihan sekolah klien.
?search=SMK&limit=10&with_demo=false{
"status": "success",
"data": [
{
"id": "school-uuid-1",
"name": "SMK Negeri 1 Jakarta",
"app_url": "https://smkn1jakarta.sekolah.kunci.test",
"logo_url": "https://kunci.co.id/storage/logos/smk1.png"
}
]
}F. Integrasi Mudah Menggunakan SDK Resmi (Direkomendasikan)
Untuk mempercepat integrasi dan menghindari kesalahan implementasi PKCE manual, Kunci menyediakan SDK resmi untuk PHP dan Dart/Flutter.
Instalasi via Composer:
composer require kunci/sso-sdk-phpBagi pengguna Laravel, Anda dapat mempublikasikan file konfigurasi:
php artisan vendor:publish --tag=kunci-sso-configSDK secara otomatis mendaftarkan Kunci\SSO\KunciSSOClient ke service container. Anda dapat langsung menginjeksikannya di Controller:
use Kunci\SSO\KunciSSOClient;
use Illuminate\Http\Request;
use Illuminate\SupportStr;
class SSOController extends Controller
{
public function redirect(KunciSSOClient $sso)
{
$pkce = $sso->generatePKCE();
session(['sso_state' => $state = Str::random(40)]);
session(['sso_code_verifier' => $pkce['code_verifier']]);
return redirect($sso->getAuthorizationUrl($state, $pkce['code_challenge']));
}
public function callback(Request $request, KunciSSOClient $sso)
{
if (!$sso->validateState(session('sso_state'), $request->state)) {
abort(403, 'Invalid state');
}
$user = $sso->exchangeCodeForUser($request->code, session('sso_code_verifier'));
// $user berisi: ['id' => '...', 'name' => '...', 'email' => '...', 'roles' => [...]]
}
}Contoh penggunaan manual (Non-Laravel / Native PHP):
$sso = new \Kunci\SSO\KunciSSOClient([
'client_id' => 'client-id-anda',
'client_secret' => 'client-secret-anda',
'redirect_uri' => 'https://sekolah.sch.id/oauth/callback',
'central_url' => 'https://kunci.co.id',
'portal_url' => 'https://kunci.co.id/portal'
]);4. Endpoint Integrasi Sekolah (Local School API)
Untuk aplikasi yang bertindak sebagai sistem sekolah lokal, Anda wajib menyediakan tiga endpoint backend-to-backend berikut. Semua request dari server pusat akan menyertakan header Authorization: Bearer CLIENT_SECRET (menggunakan Client Secret aplikasi sekolah Anda yang terdaftar di portal pusat).
4.1 Verifikasi Kredensial Sekolah
Endpoint ini dipicu oleh server pusat untuk memverifikasi kredensial login lokal pengguna sekolah saat memilih login langsung melalui portal pusat.
| Parameter | Tipe | Keterangan |
|---|---|---|
identifier | String | Username, Email, NIP, atau NIPD lokal di sekolah. |
password | String | Password akun lokal di sekolah. |
type | String | Jenis akun. Bernilai staff (Karyawan/Guru) atau student (Siswa). |
{
"identifier": "NIP / NIPD / Username / Email Lokal",
"password": "Password Akun Sekolah Lokal",
"type": "staff"
}{
"status": "success",
"name": "Ridwan Gunawan",
"email": "ridwan@sekolah.sch.id",
"photo_url": "https://sekolah.sch.id/storage/avatars/ridwan.png", // Opsional
"type": "staff"
}4.2 Sinkronisasi / Hubungkan Akun (Account Binding)
Dipanggil oleh server pusat untuk menghubungkan akun lokal sekolah pengguna dengan email SSO pusat ketika inisiasi tautan akun dilakukan dari portal.
| Parameter | Tipe | Keterangan |
|---|---|---|
app_id | String | Client ID aplikasi yang menautkan. |
identifier | String | Username, Email, NIP, atau NIPD lokal. |
pin | String | Password akun lokal. |
type | String | Tipe akun: staff atau student. |
sso_email | String | Email SSO pusat yang akan dihubungkan ke akun lokal ini. |
{
"app_id": "demosmk-client-id",
"identifier": "NIP / NIPD / Username / Email Lokal",
"pin": "Password Akun Sekolah Lokal",
"type": "staff",
"sso_email": "ridwan@sekolah.sch.id"
}{
"status": "success",
"message": "Akun Staff berhasil dihubungkan ke SSO."
}4.3 Putuskan Hubungan Akun (Account Unbinding)
Dipanggil untuk memutuskan hubungan antara akun lokal sekolah dengan email SSO pusat.
| Parameter | Tipe | Keterangan |
|---|---|---|
app_id | String | Client ID aplikasi. |
bind_id | String | ID tautan (bind) yang ingin diputuskan. |
{
"app_id": "demosmk-client-id",
"bind_id": "bind-id-to-remove"
}{
"status": "success",
"message": "Akun berhasil diputuskan dari SSO."
}5. Penanganan Error & Kode Respon
Berikut adalah daftar kode respon HTTP standar yang dapat terjadi selama pertukaran atau verifikasi:
| HTTP Kode | Deskripsi | Kemungkinan Penyebab |
|---|---|---|
| 400 Bad Request | Parameter tidak valid / Mismatch | code_verifier salah, code kedaluwarsa (berlaku 5 menit), atau mismatch redirect_uri. |
| 401 Unauthorized | Kredensial salah | client_secret tidak valid atau Authorization Bearer token salah. |
| 403 Forbidden | Sekolah Tidak Aktif | Aplikasi atau sekolah lokal dinonaktifkan di portal pusat. |
| 404 Not Found | Aplikasi tidak ditemukan | client_id tidak terdaftar di portal pusat. |
| 422 Unprocessable | Kegagalan Validasi Akun | Kredensial lokal (username/password) sekolah salah sewaktu proses verifikasi. |