ptpn/ion-client

Official PHP/Laravel client for ION SSO API

Maintainers

Package info

github.com/yusren/ion-client

Homepage

Issues

pkg:composer/ptpn/ion-client

Transparency log

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

1.0.1 2026-06-20 14:31 UTC

This package is auto-updated.

Last update: 2026-07-23 22:17:39 UTC


README

Official PHP/Laravel client SDK untuk mengonsumsi API ION SSO v2.

Latest Version on Packagist License

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 IonClient siap 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, method callback() akan melewati seluruh proses SSO dan langsung redirect ke frontend. Ini memungkinkan aplikasi consumer untuk menggunakan auth Laravel/default atau provider autentikasi lainnya. Gunakan IonClient::isEnabled() untuk mengecek status integrasi SSO di kode aplikasi.

  1. Menukar code dengan session_id dari SSO melalui verify().
    • Request ke POST /api/v2/auth/verify dengan body JSON:
      {
          "code": "AUTH_CODE_DARI_CALLBACK",
          "client_key": "your-client-key",
          "client_identifier": "your-client-identifier"
      }
    • client_identifier dikirim di body, bukan di URL atau header X-Client-Secret.
  2. Membuat session lokal Laravel dengan ID yang sama persis dengan SSO session ID.
  3. Mengambil data lengkap user dari SSO.
  4. Menyimpan data user ke session.
  5. Set cookie session ke browser.
  6. 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 level debug (misalnya kode masuk, hasil verify(), session ID yang diekstrak, kunci data session yang disimpan, konfigurasi cookie, dan tujuan redirect). Aktifkan APP_DEBUG=true atau channel log debug saat 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-ID
  • X-Client-Secret
  • X-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_number sebelum dikirim.
  • Field recipient_id tetap 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 menukar code menjadi 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.