ptpn / ion-client
Official PHP/Laravel client for ION SSO API
Package info
pkg:composer/ptpn/ion-client
Requires
- php: ^7.3|^8.0
- guzzlehttp/guzzle: ^6.5|^7.0
- illuminate/http: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/support: ^8.0|^9.0|^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^6.0|^7.0|^8.0|^9.0|^10.0
- phpunit/phpunit: ^9.0|^10.0|^11.0
README
Official PHP/Laravel client SDK untuk mengonsumsi API ION SSO v2.
Fitur
- Dukungan Laravel 8, 9, 10, 11, dan 12.
- PHP 7.3+ dan PHP 8.x.
- Menggunakan GuzzleHTTP sebagai HTTP client.
- Laravel package auto-discovery.
- Facade
IonClientsiap pakai. - Config publishable.
- Custom exception
IonClientException.
Instalasi
Install package melalui Composer:
composer require ptpn/ion-client
Konfigurasi
Publish file konfigurasi ke project Laravel:
php artisan vendor:publish --tag=ion-client-config
Setelah dipublish, file config/ion-client.php akan tersedia. Tambahkan environment variables berikut di .env:
# Aktifkan/nonaktifkan ION SSO client ION_ENABLED=true # Konfigurasi API ION ION_BASE_URL=https://ion.palmco.id ION_CLIENT_KEY=your-client-key ION_CLIENT_IDENTIFIER=your-client-identifier ION_TIMEOUT=30 ION_VERIFY_SSL=true # URL frontend yang menjadi tujuan redirect setelah SSO callback ION_FRONTEND_URL=http://localhost:9000 # Pengaturan cookie session setelah callback SSO ION_COOKIE_NAME=ion_session ION_COOKIE_LIFETIME=1440 ION_COOKIE_DOMAIN=localhost ION_COOKIE_SECURE=false ION_COOKIE_HTTP_ONLY=true ION_COOKIE_SAMESITE=Lax
Alur Autentikasi SSO
Package ini mengikuti alur redirect-based SSO dengan tiga step utama. Perhatikan bahwa client_identifier (secret) tidak lagi dikirim di Step 1 — secret hanya dikirim di Step 3 melalui back-channel.
Step 1 (browser) Step 2 (browser) Step 3 (server-to-server)
│ │ │
▼ ▼ ▼
Redirect ke SSO SSO redirect kembali Backend kirim POST /api/v2/auth/verify
/auth/login ke /auth/callback?code=xxx dengan JSON body:
?client_key=xxx │ {
&redirect_uri=yyy │ "code": "xxx",
│ "client_key": "xxx",
│ "client_identifier": "yyy"
│ }
Penting: client_identifier hanya muncul di Step 3 (JSON body). Ia tidak pernah muncul di URL, browser history, access log, atau header X-Client-Secret saat verify().
Penggunaan
Step 1 — Redirect User ke SSO Login
Gunakan method getLoginUrl() untuk membangun URL login SSO. URL ini aman dibagikan ke browser karena hanya mengandung client_key dan redirect_uri. Secret client_identifier tidak pernah muncul di URL.
use IonClient; $loginUrl = IonClient::getLoginUrl( redirectUri: 'https://app.example.com/auth/callback', ); return redirect($loginUrl);
Secara default, jika redirectUri tidak diberikan, akan digunakan ION_FRONTEND_URL/auth/callback.
SSO Callback
Setelah user berhasil login di ION SSO, SSO server akan redirect ke callback URL aplikasi client dengan membawa query parameter code. Package ini menyediakan method callback() yang menangani seluruh alur tersebut.
ION_ENABLED: Jika
ION_ENABLED=false, methodcallback()akan melewati seluruh proses SSO dan langsung redirect ke frontend. Ini memungkinkan aplikasi consumer untuk menggunakan auth Laravel/default atau provider autentikasi lainnya. GunakanIonClient::isEnabled()untuk mengecek status integrasi SSO di kode aplikasi.
- Menukar
codedengansession_iddari SSO melaluiverify().- Request ke
POST /api/v2/auth/verifydengan body JSON:{ "code": "AUTH_CODE_DARI_CALLBACK", "client_key": "your-client-key", "client_identifier": "your-client-identifier" } client_identifierdikirim di body, bukan di URL atau headerX-Client-Secret.
- Request ke
- Membuat session lokal Laravel dengan ID yang sama persis dengan SSO session ID.
- Mengambil data lengkap user dari SSO.
- Menyimpan data user ke session.
- Set cookie session ke browser.
- Redirect browser ke frontend.
Buat route callback di aplikasi Laravel:
use Illuminate\Support\Facades\Route; use Ptpn\IonClient\IonClient; Route::get('/auth/callback', function (\Illuminate\Http\Request $request) { return app(IonClient::class)->callback($request); });
Atau menggunakan Facade:
use Illuminate\Support\Facades\Route; use IonClient; Route::get('/auth/callback', function (\Illuminate\Http\Request $request) { return IonClient::callback($request); });
Debug:
callback()mencatat event penting ke Laravel log pada leveldebug(misalnya kode masuk, hasilverify(), session ID yang diekstrak, kunci data session yang disimpan, konfigurasi cookie, dan tujuan redirect). AktifkanAPP_DEBUG=trueatau channel logdebugsaat menganalisis masalah SSO.
Penting: session lokal dibuat dengan ID yang sama dengan SSO session ID. Hal ini diperlukan agar webhook logout dari SSO dapat menghapus session lokal berdasarkan ID tersebut.
Menggunakan Facade
use IonClient; // Cek session $session = IonClient::checkSession($sessionId); // Verifikasi auth code $user = IonClient::verify('AUTH_CODE_HERE'); // Ambil data session lengkap $fullInfo = IonClient::getSessionFullInfo($sessionId); // Ambil role user untuk aplikasi tertentu $roles = IonClient::getUserRoles($sessionId, 'hris'); // Heartbeat agar session tetap aktif IonClient::heartbeat($sessionId); // Logout user (trigger pemutusan session ke SSO) IonClient::logout($sessionId);
Menggunakan Dependency Injection
use Illuminate\Http\Request; use Ptpn\IonClient\IonClient; class AuthController extends Controller { protected $ion; public function __construct(IonClient $ion) { $this->ion = $ion; } public function logout(Request $request) { try { $data = $this->ion->logout($request->input('session_id')); return response()->json($data); } catch (\Ptpn\IonClient\Exceptions\IonClientException $e) { return response()->json(['error' => $e->getMessage()], 500); } } }
Daftar Method
| Method | Endpoint | Deskripsi |
|---|---|---|
checkSession($sessionId) |
GET /api/v2/auth/check-session |
Cek apakah session SSO masih aktif. |
verify($code) |
POST /api/v2/auth/verify |
Tukar auth code menjadi session ID + data user. |
getSessionFullInfo($sessionId) |
POST /api/v2/client/session/full-info |
Ambil data session lengkap. |
getUserRoles($sessionId, $application) |
POST /api/v2/client/user/roles |
Ambil daftar role user untuk app tertentu. |
getLoginUrl($redirectUri, $extra) |
— | Bangun URL redirect SSO login (Step 1). Hanya mengandung client_key + redirect_uri. |
heartbeat($sessionId) |
POST /api/v2/client/heartbeat |
Pertahankan session tetap aktif. |
logout($sessionId) |
POST /api/v2/client/logout |
Logout user session (trigger putus ke SSO). |
callback($request) |
POST /api/v2/auth/verify + POST /api/v2/client/session/full-info |
Handle SSO callback, buat session lokal, set cookie, redirect ke frontend. |
Header Wajib
Hampir semua request ke ION otomatis menyertakan header wajib:
X-Client-IDX-Client-SecretX-Timestamp
Pengecualian: verify() (Step 3, back-channel token exchange) tidak mengirim header X-Client-Secret. Credential (client_key dan client_identifier) dikirim dalam JSON body sesuai flow SSO terbaru.
Struktur Data SSO
Berikut adalah struktur data yang dikembalikan oleh ION SSO dan cara menggunakannya di aplikasi client.
1. Request & Response Verifikasi (POST /auth/verify)
Method verify($code) mengirim request ke POST /auth/verify dengan body:
{
"code": "AUTH_CODE_DARI_CALLBACK",
"client_key": "your-client-key",
"client_identifier": "your-client-identifier"
}
Response yang dikembalikan:
| Field | JSON Key | Keterangan |
|---|---|---|
User.SessionID |
user.session_id |
Session ID dari SSO |
User.Email |
user.email |
Email user |
Error |
error |
Pesan error jika gagal |
{
"user": {
"session_id": "sso-session-abc123",
"email": "user@example.com"
},
"error": ""
}
2. Data User Lengkap (POST /client/session/full-info)
Method getSessionFullInfo($sessionId) mengembalikan data user lengkap:
| Field | JSON Key | Tipe | Keterangan |
|---|---|---|---|
Username |
username |
string | Username / NIK SAP |
SessionID |
session_id |
string | SSO Session ID |
HashUserID |
hash_user_id |
string | Hash ID user |
NikSAP |
nik_sap |
string | NIK SAP karyawan |
UserRole |
user_role |
string | Role user, delimiter ; |
ExpiresAt |
expires_at |
datetime | Waktu expired session |
Locale |
locale |
string | Bahasa, contoh: id, en |
Name |
name |
string | Nama lengkap |
PositionName |
position_name |
string | Nama jabatan |
DepartmentName |
department_name |
string | Nama departemen |
UnitName |
unit_name |
string | Nama unit |
UnitCode |
unit_code |
string | Kode unit |
CompanyName |
company_name |
string | Nama perusahaan |
Gender |
gender |
bool | Jenis kelamin |
TelegramID |
telegram_id |
string | ID Telegram |
CellphoneNumber |
cellphone_number |
string | Nomor HP |
HashRecipientId |
recipient_id |
string | Hash recipient ID |
CompanyID |
company_id |
int64 | ID perusahaan asli |
UnitID |
unit_id |
int64 | ID unit asli |
DepartmentID |
department_id |
int64 | ID departemen asli |
PositionID |
position_id |
int64 | ID jabatan asli |
LevelElemen |
level_elemen |
uint8 | Level elemen user |
{
"message": "success",
"data": {
"session_id": "sso-session-abc123",
"hash_user_id": "abc123",
"nik_sap": "88888888",
"username": "88888888",
"user_role": "GENERAL_USER;PROTON_CREATOR;MEMO_CREATOR",
"expires_at": "2026-06-12T09:27:21Z",
"locale": "id",
"name": "Karyawan Teladan",
"position_name": "Officer Data Support",
"department_name": "Divisi Teknologi Informasi & Sistem Manajemen",
"unit_name": "Head Office",
"unit_code": "HO",
"company_name": "PT Perkebunan Nusantara IV",
"gender": true,
"telegram_id": "",
"cellphone_number": "081234567890",
"recipient_id": "xyz789",
"company_id": 2,
"unit_id": 2,
"department_id": 53,
"position_id": 1631,
"level_elemen": 1
}
}
3. Data User untuk Frontend
Saat mengirim data user ke frontend, sebaiknya:
- Sembunyikan ID integer asli (
company_id,unit_id,department_id,position_id). Gunakan versi hash-nya. - Masking data sensitif seperti
username,nik_sap,telegram_id,cellphone_numbersebelum dikirim. - Field
recipient_idtetap dikirim sebagai hash.
Contoh response ke frontend:
{
"message": "Authenticated",
"authenticated": true,
"data": {
"session_id": "sso-session-abc123",
"hash_user_id": "abc123",
"nik_sap": "88888888",
"username": "88888888",
"user_role": "GENERAL_USER;PROTON_CREATOR;MEMO_CREATOR",
"expires_at": "2026-06-12T09:27:21Z",
"locale": "id",
"name": "Karyawan Teladan",
"position_name": "Officer Data Support",
"department_name": "Divisi Teknologi Informasi & Sistem Manajemen",
"unit_name": "Head Office",
"unit_code": "HO",
"company_name": "PT Perkebunan Nusantara IV",
"gender": true,
"telegram_id": "",
"cellphone_number": "08*****7890",
"recipient_id": "xyz789",
"company_id": "hash-company-1",
"unit_id": "hash-unit-1",
"department_id": "hash-dept-1",
"position_id": "hash-position-1",
"level_elemen": 1
}
}
4. User Roles (POST /client/user/roles)
Method getUserRoles($sessionId, $application) mengembalikan:
| Field | JSON Key | Keterangan |
|---|---|---|
ApplicationCode |
application_code |
Kode aplikasi |
UserRoles |
user_roles |
Role user, delimiter ; |
{
"message": "success",
"data": {
"application_code": "elemen",
"user_roles": "GENERAL_USER;ADMIN"
}
}
Di PHP, role bisa diubah menjadi array dengan:
$roles = explode(';', $response['data']['user_roles']);
Catatan Tentang Login
Package client ini tidak menyediakan fitur login dengan username/password. Proses autentikasi pengguna (memasukkan kredensial) berjalan di sisi ION SSO melalui redirect/resmi SSO. Client hanya menyediakan:
getLoginUrl()— membangun URL redirect ke halaman login SSO (Step 1).callback($request)— menangani redirect balik dari SSO dan menukarcodemenjadi session (Step 2 & 3).verify($code)— menukar authorization code hasil redirect SSO menjadi session ID dan data user.checkSession($sessionId)— memvalidasi session yang sudah ada.
Logout tetap disediakan agar aplikasi client dapat memberitahu ION SSO bahwa session pengguna harus dihapus.
Penanganan Error
Semua error HTTP maupun error dari response ION akan dilempar sebagai Ptpn\IonClient\Exceptions\IonClientException. Pesan error akan diambil dari field message atau error pada response JSON ION jika tersedia.
use Ptpn\IonClient\Exceptions\IonClientException; try { $user = IonClient::verify('AUTH_CODE_HERE'); } catch (IonClientException $e) { // $e->getMessage() berisi pesan error dari ION logger()->error($e->getMessage()); }
Testing
Jalankan PHPUnit setelah menginstall dependency:
composer install vendor/bin/phpunit
License
Package ini dirilis di bawah lisensi MIT.