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 KredensialTipeDeskripsi / Peran
client_idStringPengidentifikasi publik unik untuk aplikasi sekolah klien Anda. Dikirim secara terbuka saat inisiasi otorisasi.
client_secretStringKunci rahasia klien. Wajib dijaga kerahasiaannya di server backend Anda. Digunakan untuk menukar code dan verifikasi webhook.
redirect_uriURLURL callback yang diizinkan untuk menerima kode otorisasi dari portal. Wajib didaftarkan persis di dashboard central.
Keamanan Penting: Jangan pernah menyimpan 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).
Cara Memperoleh Kredensial: Pengajuan integrasi aplikasi baru (baik sekolah lokal maupun pihak ketiga) diproses secara manual oleh administrator. Kirimkan detail aplikasi Anda (Nama aplikasi, redirect URI, dan allowed domains) via email ke hallo@kunci.co.id. Kredensial 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
1

Inisiasi Login Klien

Pengguna memilih login SSO di website sekolah. Website sekolah membuat random string code_verifier & hashing S256 code_challenge.

2

Pengalihan ke Portal Pusat

Pengguna diarahkan ke halaman otorisasi portal pusat membawa parameter client ID, redirect URI, scope, state, dan challenge.

3

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.

4

Pengembalian Code Otorisasi

Portal mengalihkan browser kembali ke redirect URI website sekolah dengan menyertakan parameter code dan state asal.

5

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 -, ., _, ~.

Implementasi PHP (Laravel / Native)
// 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:

ParameterStatusKeterangan
client_idWajibID Klien yang Anda dapatkan dari portal pusat.
redirect_uriWajibURL callback untuk menerima output code. Harus persis dengan yang didaftarkan.
response_typeWajibIsi dengan string literal code.
scopeOpsionalInformasi yang diminta, dipisahkan oleh spasi (contoh: profile email).
code_challengeWajibString challenge hasil SHA256 base64url dari code_verifier Anda.
code_challenge_methodWajibMetode hashing. Harus bernilai S256.
stateOpsionalRandom string unik untuk mencegah CSRF attack. Server Anda wajib memverifikasi nilai ini pada callback.
Contoh Endpoint GET /oauth/authorize
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=xyzSecretState

C. 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:

POST/sso/exchange
Parameter BodyTipeKeterangan
client_idStringID Klien yang Anda miliki.
client_secretStringRahasia klien aplikasi Anda. Hanya dikirim dari server-to-server.
codeStringKode otorisasi yang didapatkan dari query params redirect callback.
code_verifierStringRandom string verifier asli yang digunakan untuk menghasilkan challenge di Langkah 1.
redirect_uriStringURI pengalihan asli. Harus sama persis dengan Langkah 1.
Payload Request (JSON)
{
  "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"
}
Response Sukses (JSON)
{
  "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.

GET/sso/schools
Query Parameter (Opsional)
?search=SMK&limit=10&with_demo=false
Response Sukses (JSON)
{
  "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:

Terminal
composer require kunci/sso-sdk-php

Bagi pengguna Laravel, Anda dapat mempublikasikan file konfigurasi:

Publish Config
php artisan vendor:publish --tag=kunci-sso-config

SDK secara otomatis mendaftarkan Kunci\SSO\KunciSSOClient ke service container. Anda dapat langsung menginjeksikannya di Controller:

Penggunaan di Controller Laravel
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):

Manual Instantiation
$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)

Info Pihak Ketiga (Third-Party SaaS): Jika Anda mengintegrasikan aplikasi pihak ketiga (seperti LMS eksternal, sistem perpustakaan, atau kantin digital) dan tidak memiliki database sekolah lokal sendiri, Anda TIDAK PERLU mengimplementasikan endpoint sinkronisasi (verify, bind, unbind) di bawah ini. Anda cukup menggunakan alur otorisasi standar (Langkah 1 s.d. 3) untuk mengotentikasi pengguna dan mendapatkan data profil mereka dari portal pusat.

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.

POST/api/sso/account/verify
ParameterTipeKeterangan
identifierStringUsername, Email, NIP, atau NIPD lokal di sekolah.
passwordStringPassword akun lokal di sekolah.
typeStringJenis akun. Bernilai staff (Karyawan/Guru) atau student (Siswa).
Payload Request (JSON)
{
  "identifier": "NIP / NIPD / Username / Email Lokal",
  "password": "Password Akun Sekolah Lokal",
  "type": "staff"
}
Response Sukses (JSON)
{
  "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.

POST/api/sso/account/bind
ParameterTipeKeterangan
app_idStringClient ID aplikasi yang menautkan.
identifierStringUsername, Email, NIP, atau NIPD lokal.
pinStringPassword akun lokal.
typeStringTipe akun: staff atau student.
sso_emailStringEmail SSO pusat yang akan dihubungkan ke akun lokal ini.
Payload Request (JSON)
{
  "app_id": "demosmk-client-id",
  "identifier": "NIP / NIPD / Username / Email Lokal",
  "pin": "Password Akun Sekolah Lokal",
  "type": "staff",
  "sso_email": "ridwan@sekolah.sch.id"
}
Response Sukses (JSON)
{
  "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.

POST/api/sso/account/unbind
ParameterTipeKeterangan
app_idStringClient ID aplikasi.
bind_idStringID tautan (bind) yang ingin diputuskan.
Payload Request (JSON)
{
  "app_id": "demosmk-client-id",
  "bind_id": "bind-id-to-remove"
}
Response Sukses (JSON)
{
  "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 KodeDeskripsiKemungkinan Penyebab
400 Bad RequestParameter tidak valid / Mismatchcode_verifier salah, code kedaluwarsa (berlaku 5 menit), atau mismatch redirect_uri.
401 UnauthorizedKredensial salahclient_secret tidak valid atau Authorization Bearer token salah.
403 ForbiddenSekolah Tidak AktifAplikasi atau sekolah lokal dinonaktifkan di portal pusat.
404 Not FoundAplikasi tidak ditemukanclient_id tidak terdaftar di portal pusat.
422 UnprocessableKegagalan Validasi AkunKredensial lokal (username/password) sekolah salah sewaktu proses verifikasi.