---
# System prepended metadata

title: WordPress SSO Integration Documentation

---

# WordPress SSO Integration Documentation

## Overview
This document describes the WordPress SSO integration between WordPress (host) and HG RO application (client). WordPress retrieves user data from ESS system and passes it to the HG RO client via SSO using POST method.

## Updated Client Endpoints
- **Login**: `https://hg-ro.com/sso/wordpress/login` (POST method only)
- **Logout**: `https://hg-ro.com/sso/wordpress/logout` (POST method only)

## WordPress Host Information
- **WordPress Host URL**: `https://ro.hasnurgroup.com`
- **Validation Endpoint**: `https://ro.hasnurgroup.com/wp-json/sso/v1/validate-token`

## Secret Key Configuration

### Mendapatkan SSO_WORDPRESS_SECRET_KEY

**SSO_WORDPRESS_SECRET_KEY** adalah kunci rahasia yang harus **disepakati bersama** antara:
- **Tim HG RO** - sebagai client
- **Tim WordPress di ro.hasnurgroup.com** - sebagai host

### Langkah-langkah Koordinasi:

**1. Hubungi Administrator WordPress ro.hasnurgroup.com:**
```
Subject: Request WordPress SSO Integration - Secret Key

Kepada Tim WordPress ro.hasnurgroup.com,

Kami membutuhkan integrasi WordPress SSO dengan aplikasi HG RO.
Mohon dapat dibuatkan:

1. Secret Key untuk SSO integration
2. Implementasi endpoint validation: /wp-json/sso/v1/validate-token
3. Konfigurasi ESS data mapping di WordPress

Endpoint client kami:
- Login: https://hg-ro.com/sso/wordpress/login (POST method)
- Logout: https://hg-ro.com/sso/wordpress/logout (POST method)

Dokumentasi lengkap terlampir.

Terima kasih.
```

**2. Saran Secret Key yang Aman:**
```php
// Contoh secret key yang kuat (32+ karakter)
SSO_WORDPRESS_SECRET_KEY=HG_RO_WP_SSO_2024_SecureKey_xyz789ABC
```

**3. Update .env File:**
Setelah mendapat secret key dari tim WordPress:
```env
# WordPress SSO Configuration
SSO_WORDPRESS_HOST_URL=https://ro.hasnurgroup.com
SSO_WORDPRESS_SECRET_KEY=your-received-secret-key-from-wordpress-team
```

**4. Informasi untuk Tim WordPress:**
```
Endpoint yang perlu dibuat di WordPress:
POST https://ro.hasnurgroup.com/wp-json/sso/v1/validate-token

Data yang dikirim dari HG RO:
- token: string (security token)
- nrp: string (user NRP)
- ts: integer (timestamp)
- secret_key: string (shared secret)

Response yang diharapkan:
{
  "valid": true/false,
  "message": "validation message",
  "user_data": { ... } // optional
}

Secret Key yang disepakati: [tunggu konfirmasi dari mereka]
```

**5. Timeline Koordinasi:**
1. **Hari 1-2:** Kirim dokumentasi ke tim WordPress
2. **Hari 3-5:** Tunggu implementasi endpoint WordPress
3. **Hari 6:** Testing integration
4. **Hari 7:** Go live

## Testing Sementara

Untuk testing sebelum koordinasi dengan WordPress, gunakan mock:

```env
# Testing configuration
SSO_WORDPRESS_HOST_URL=http://localhost
SSO_WORDPRESS_SECRET_KEY=test-secret-key-123
```

Dan tambahkan mock endpoint di `routes/web.php`:
```php
// Mock WordPress validation for testing
Route::post('/wp-json/sso/v1/validate-token', function(Request $request) {
    $params = $request->all();
    
    if ($params['secret_key'] !== 'test-secret-key-123') {
        return response()->json(['valid' => false, 'message' => 'Invalid secret key'], 401);
    }
    
    if ($params['nrp'] === '1250018') {
        return response()->json([
            'valid' => true,
            'message' => 'WordPress SSO token is valid'
        ]);
    }
    
    return response()->json(['valid' => false, 'message' => 'User not found']);
});
```

## Required Data Structure

### Data yang Harus Diberikan Host (WordPress) ke Client (HG RO)

WordPress harus memberikan data dalam format berikut via **POST request**:

```php
$sso_data = array(
    // REQUIRED FIELDS
    'nrp' => '1250018',                                    // NRP karyawan (wajib)
    'nama' => 'AMELIA AQILA',                             // Nama lengkap karyawan (wajib)
    
    // OPTIONAL FIELDS (dari ESS)
    'email_kantor' => 'AMELIA.AQILA@HASNURGROUP.COM',     // Email kantor (opsional)
    'posisi' => 'Staff IT',                               // Posisi/jabatan (opsional)
    'pangkat' => 'II/A',                                  // Pangkat (opsional)
    'sbu' => 'IT Department',                             // Strategic Business Unit (opsional)
    'no_handphone' => '081234567890',                     // Nomor HP (opsional)
    
    // SECURITY FIELDS
    'token' => 'generated_security_token',                 // Token keamanan (wajib)
    'ts' => 1754011429,                                   // Timestamp (wajib)
    'expires_at' => 1754011489                            // Waktu expired token (wajib)
);
```

## Host Requirements (WordPress Side)

### 1. WordPress SSO Integration dengan HG RO

**IMPORTANT**: HG RO hanya menerima **POST request** untuk WordPress SSO login.

```php
// WordPress function to send POST request to HG RO
function send_wordpress_sso_to_hg_ro($user_id) {
    $user = get_user_by('id', $user_id);
    $secret_key = 'your-shared-secret-key'; // Must match HG RO config
    
    // Get ESS data for this user (implement your ESS integration here)
    $ess_data = get_user_ess_data($user_id); // Your custom function to get ESS data
    
    $sso_data = array(
        // Required fields
        'nrp' => $ess_data['nrp'] ?? $user->user_login,
        'nama' => $ess_data['nama'] ?? $user->display_name,
        
        // Optional ESS fields
        'email_kantor' => $ess_data['email_kantor'] ?? $user->user_email,
        'posisi' => $ess_data['posisi'] ?? '',
        'pangkat' => $ess_data['pangkat'] ?? '',
        'sbu' => $ess_data['sbu'] ?? '',
        'no_handphone' => $ess_data['no_handphone'] ?? '',
        
        // Security fields
        'token' => hash('sha256', $ess_data['nrp'] . $ess_data['nama'] . time() . $secret_key),
        'ts' => time(),
        'expires_at' => time() + 60 // Token expires in 60 seconds
    );
    
    // Send POST request to HG RO
    $response = wp_remote_post('https://hg-ro.com/sso/wordpress/login', array(
        'method' => 'POST',
        'timeout' => 30,
        'headers' => array(
            'Content-Type' => 'application/json',
            'Accept' => 'application/json'
        ),
        'body' => json_encode($sso_data)
    ));
    
    if (is_wp_error($response)) {
        error_log('WordPress SSO to HG RO failed: ' . $response->get_error_message());
        return false;
    }
    
    $response_body = wp_remote_retrieve_body($response);
    $result = json_decode($response_body, true);
    
    if ($result['status'] === 'success') {
        // Redirect user to HG RO dashboard or provided redirect URL
        wp_redirect($result['redirect_url']);
        exit;
    } else {
        error_log('HG RO SSO login failed: ' . $result['message']);
        return false;
    }
}

// Alternative: Create form with auto-submit for POST redirect
function create_wordpress_sso_form_to_hg_ro($user_id) {
    $user = get_user_by('id', $user_id);
    $secret_key = 'your-shared-secret-key';
    
    $ess_data = get_user_ess_data($user_id);
    
    $sso_data = array(
        'nrp' => $ess_data['nrp'] ?? $user->user_login,
        'nama' => $ess_data['nama'] ?? $user->display_name,
        'email_kantor' => $ess_data['email_kantor'] ?? $user->user_email,
        'posisi' => $ess_data['posisi'] ?? '',
        'pangkat' => $ess_data['pangkat'] ?? '',
        'sbu' => $ess_data['sbu'] ?? '',
        'no_handphone' => $ess_data['no_handphone'] ?? '',
        'token' => hash('sha256', $ess_data['nrp'] . $ess_data['nama'] . time() . $secret_key),
        'ts' => time(),
        'expires_at' => time() + 60
    );
    
    // Create auto-submit form
    echo '<form id="sso-form" method="POST" action="https://hg-ro.com/sso/wordpress/login">';
    foreach ($sso_data as $key => $value) {
        echo '<input type="hidden" name="' . esc_attr($key) . '" value="' . esc_attr($value) . '">';
    }
    echo '</form>';
    echo '<script>document.getElementById("sso-form").submit();</script>';
}

// Example button in WordPress admin/frontend
function display_wordpress_sso_button_for_hg_ro() {
    if (is_user_logged_in()) {
        $user_id = get_current_user_id();
        
        echo '<form method="post" action="' . admin_url('admin-post.php') . '">';
        echo '<input type="hidden" name="action" value="sso_login_to_hg_ro">';
        echo '<input type="hidden" name="user_id" value="' . $user_id . '">';
        echo '<button type="submit" class="button button-primary">Login to HG RO via WordPress SSO</button>';
        echo '</form>';
    }
}

// Handle the form submission
add_action('admin_post_sso_login_to_hg_ro', 'handle_sso_login_to_hg_ro');
function handle_sso_login_to_hg_ro() {
    $user_id = intval($_POST['user_id']);
    
    if (!$user_id || !current_user_can('read')) {
        wp_die('Unauthorized');
    }
    
    create_wordpress_sso_form_to_hg_ro($user_id);
}

// Hook to display button in admin area
add_action('admin_notices', 'display_wordpress_sso_button_for_hg_ro');
```

### 2. WordPress Token Validation API Endpoint

```php
// Add to functions.php or plugin
add_action('rest_api_init', function () {
    register_rest_route('sso/v1', '/validate-token', array(
        'methods' => 'POST',
        'callback' => 'validate_wordpress_sso_token',
        'permission_callback' => '__return_true'
    ));
});

function validate_wordpress_sso_token($request) {
    $params = $request->get_params();
    $secret_key = 'your-shared-secret-key'; // Must match HG RO config
    
    // Log validation attempt for WordPress SSO
    error_log('WordPress SSO token validation attempt: ' . json_encode($params));
    
    // Validate required parameters
    if (!isset($params['token']) || !isset($params['nrp']) || !isset($params['ts']) || !isset($params['secret_key'])) {
        return new WP_Error('missing_params', 'Missing required WordPress SSO parameters', array('status' => 400));
    }
    
    // Validate secret key - IMPORTANT: Ganti dengan secret key yang disepakati
    if ($params['secret_key'] !== $secret_key) {
        error_log('WordPress SSO: Invalid secret key provided');
        return new WP_Error('invalid_secret', 'Invalid WordPress SSO secret key', array('status' => 401));
    }
    
    // Get user by NRP (implement your user lookup logic)
    $user_data = get_user_by_nrp($params['nrp']); // Your custom function
    if (!$user_data) {
        error_log('WordPress SSO: User not found - ' . $params['nrp']);
        return array('valid' => false, 'message' => 'WordPress user not found');
    }
    
    // Validate token (recreate and compare)
    $expected_token = hash('sha256', $user_data['nrp'] . $user_data['nama'] . $params['ts'] . $secret_key);
    
    if ($params['token'] === $expected_token) {
        error_log('WordPress SSO: Token validation successful for NRP - ' . $params['nrp']);
        return array(
            'valid' => true, 
            'message' => 'WordPress SSO token is valid',
            'user_data' => $user_data
        );
    }
    
    error_log('WordPress SSO: Token validation failed for NRP - ' . $params['nrp']);
    return array('valid' => false, 'message' => 'Invalid WordPress SSO token');
}

// Example function to get user by NRP
function get_user_by_nrp($nrp) {
    // Your logic to find user by NRP in WordPress
    // This should return ESS-like data structure
    global $wpdb;
    
    $user = $wpdb->get_row($wpdb->prepare(
        "SELECT u.*, 
         um_nrp.meta_value as nrp,
         um_nama.meta_value as nama,
         um_email.meta_value as email_kantor,
         um_posisi.meta_value as posisi,
         um_pangkat.meta_value as pangkat,
         um_sbu.meta_value as sbu,
         um_hp.meta_value as no_handphone
         FROM {$wpdb->users} u
         LEFT JOIN {$wpdb->usermeta} um_nrp ON u.ID = um_nrp.user_id AND um_nrp.meta_key = 'ess_nrp'
         LEFT JOIN {$wpdb->usermeta} um_nama ON u.ID = um_nama.user_id AND um_nama.meta_key = 'ess_nama'
         LEFT JOIN {$wpdb->usermeta} um_email ON u.ID = um_email.user_id AND um_email.meta_key = 'ess_email_kantor'
         LEFT JOIN {$wpdb->usermeta} um_posisi ON u.ID = um_posisi.user_id AND um_posisi.meta_key = 'ess_posisi'
         LEFT JOIN {$wpdb->usermeta} um_pangkat ON u.ID = um_pangkat.user_id AND um_pangkat.meta_key = 'ess_pangkat'
         LEFT JOIN {$wpdb->usermeta} um_sbu ON u.ID = um_sbu.user_id AND um_sbu.meta_key = 'ess_sbu'
         LEFT JOIN {$wpdb->usermeta} um_hp ON u.ID = um_hp.user_id AND um_hp.meta_key = 'ess_no_handphone'
         WHERE um_nrp.meta_value = %s",
        $nrp
    ));
    
    if (!$user) {
        return false;
    }
    
    return array(
        'nrp' => $user->nrp,
        'nama' => $user->nama ?: $user->display_name,
        'email_kantor' => $user->email_kantor ?: $user->user_email,
        'posisi' => $user->posisi,
        'pangkat' => $user->pangkat,
        'sbu' => $user->sbu,
        'no_handphone' => $user->no_handphone
    );
}
```

## WordPress SSO Flow Example dengan HG RO

1. **User clicks WordPress SSO button**:
   - WordPress creates auto-submit form with POST data
   - Form automatically submits to: `https://hg-ro.com/sso/wordpress/login`

2. **POST Request Data to HG RO**:
   ```json
   {
     "nrp": "1250018",
     "nama": "AMELIA AQILA",
     "email_kantor": "AMELIA.AQILA@HASNURGROUP.COM",
     "posisi": "Staff IT",
     "pangkat": "II/A",
     "sbu": "IT Department",
     "no_handphone": "081234567890",
     "token": "1345472f59a31e6baeb2e7e5adbd87c6f57449de25bca871a688bd5d4bd7f0b3",
     "ts": 1754011429,
     "expires_at": 1754011489
   }
   ```

3. **HG RO validates token with WordPress**:
   - POST to: `https://your-wordpress-site.com/wp-json/sso/v1/validate-token`
   - Sends token data back to WordPress for validation

4. **WordPress responds with validation result**:
   ```json
   {
     "valid": true,
     "message": "WordPress SSO token is valid",
     "user_data": {
       "nrp": "1250018",
       "nama": "AMELIA AQILA",
       "email_kantor": "AMELIA.AQILA@HASNURGROUP.COM"
     }
   }
   ```

5. **HG RO creates/updates user and logs in**:
   ```json
   {
     "status": "success",
     "message": "WordPress SSO login successful",
     "redirect_url": "https://hg-ro.com/dashboard",
     "user": {
       "id": 123,
       "name": "AMELIA AQILA",
       "email": "AMELIA.AQILA@HASNURGROUP.COM",
       "nrp": "1250018"
     }
   }
   ```

## Data Mapping Summary

| WordPress SSO Field | ESS Equivalent | HG RO User Field | Required |
|-------------------|----------------|------------------|----------|
| `nrp` | `nrp` | `nrp` | ✅ |
| `nama` | `nama` | `name` | ✅ |
| `email_kantor` | `email_kantor` | `email` | ❌ |
| `posisi` | `posisi` | `position` | ❌ |
| `pangkat` | `pangkat` | (AuthEss.rank) | ❌ |
| `sbu` | `sbu` | (AuthEss.sbu) | ❌ |
| `no_handphone` | `no_handphone` | `phone` | ❌ |

## Configuration Summary

### HG RO Configuration (`config/sso.php`):
```php
'wordpress_host_url' => env('SSO_WORDPRESS_HOST_URL', 'https://ro.hasnurgroup.com'),
'wordpress_secret_key' => env('SSO_WORDPRESS_SECRET_KEY'),
```

### Environment Variables (`.env`):
```env
SSO_WORDPRESS_HOST_URL=https://ro.hasnurgroup.com
SSO_WORDPRESS_SECRET_KEY=[secret-key-from-wordpress-team]
```

### CSRF Exception (`app/Http/Middleware/VerifyCsrfToken.php`):
```php
protected $except = [
    'sso/wordpress/login',
    'sso/wordpress/logout',
];
```

## WordPress SSO Security Notes
1. **Secret Key Coordination** - Wajib koordinasi dengan tim WordPress untuk secret key
2. **POST method only** - HG RO tidak menerima GET request untuk SSO login
3. Tokens expire in 60 seconds to prevent replay attacks
4. Use HTTPS for all WordPress SSO communications with HG RO
5. Validate secret key on both WordPress and HG RO sides
6. Log all WordPress SSO attempts for security monitoring
7. WordPress SSO tokens are unique per user/timestamp combination
8. CSRF protection disabled untuk endpoint SSO HG RO

## WordPress SSO Troubleshooting

### Common Issues:
1. **Secret Key Not Configured** - Koordinasi dengan tim WordPress belum selesai
2. **POST Method Required** - HG RO hanya menerima POST request, bukan GET
3. **Token Expired** - Ensure WordPress generates fresh tokens
4. **Invalid Secret** - Verify secret keys match on both sides
5. **User Not Found** - Check if WordPress user exists and is active
6. **Network Timeout** - Verify HG RO SSO endpoint is accessible
7. **CORS Issues** - Ensure proper headers when sending POST requests

### WordPress SSO Logs:
- HG RO logs: `storage/logs/laravel.log`
- WordPress logs: WordPress error logs (if enabled)
- Check both sides for complete troubleshooting

### Testing dengan Postman:
```
Method: POST
URL: https://hg-ro.com/sso/wordpress/login
Headers: 
  Content-Type: application/json
  Accept: application/json
Body: Raw JSON dengan data sesuai struktur di atas
```

**Kesimpulan:** Secret key belum ada, perlu koordinasi dengan tim WordPress ro.hasnurgroup.com untuk menyepakati secret key dan implementasi endpoint validation.

## Secret Key Configuration - Penjelasan Detail

### Apa itu Secret Key?

**Secret Key** adalah kata kunci rahasia yang digunakan untuk:
1. **Membuat token** di WordPress
2. **Memvalidasi token** di HG RO
3. **Memastikan keamanan** komunikasi antara kedua sistem

### Alur Secret Key dalam WordPress SSO

```
[WordPress] ---> [Token dengan Secret Key] ---> [HG RO] ---> [Validasi ke WordPress]
```

### Step-by-Step Alur:

**1. Koordinasi Awal - Menentukan Secret Key**
```
Tim HG RO menghubungi Tim WordPress:
"Kami butuh secret key untuk SSO integration"

Tim WordPress membuat secret key:
SSO_WORDPRESS_SECRET_KEY=HG_RO_WP_SSO_2024_SecureKey_xyz789ABC

Tim WordPress memberikan secret key ini ke Tim HG RO
```

**2. Konfigurasi di Kedua Sisi**
```
Di WordPress (Host):
$secret_key = 'HG_RO_WP_SSO_2024_SecureKey_xyz789ABC';

Di HG RO (Client):
SSO_WORDPRESS_SECRET_KEY=HG_RO_WP_SSO_2024_SecureKey_xyz789ABC
```

**3. Proses Pembuatan Token di WordPress**
```php
// Di WordPress ketika user klik tombol SSO
$nrp = '1250018';
$nama = 'AMELIA AQILA';
$timestamp = time(); // 1754011429
$secret_key = 'HG_RO_WP_SSO_2024_SecureKey_xyz789ABC';

// Token dibuat dengan menggabungkan data + secret key
$token = hash('sha256', $nrp . $nama . $timestamp . $secret_key);
// Hasil: 1345472f59a31e6baeb2e7e5adbd87c6f57449de25bca871a688bd5d4bd7f0b3
```

**4. Data yang Dikirim ke HG RO**
```json
{
  "nrp": "1250018",
  "nama": "AMELIA AQILA", 
  "token": "1345472f59a31e6baeb2e7e5adbd87c6f57449de25bca871a688bd5d4bd7f0b3",
  "ts": 1754011429,
  "expires_at": 1754011489
}
```

**5. Validasi Token di HG RO**
```php
// HG RO menerima data, lalu validasi ke WordPress
HG RO kirim ke WordPress:
{
  "token": "1345472f59a31e6baeb2e7e5adbd87c6f57449de25bca871a688bd5d4bd7f0b3",
  "nrp": "1250018",
  "ts": 1754011429,
  "secret_key": "HG_RO_WP_SSO_2024_SecureKey_xyz789ABC"
}
```

**6. Verifikasi di WordPress**
```php
// WordPress recreate token dengan data yang sama
$received_nrp = '1250018';
$received_nama = 'AMELIA AQILA'; // dari database WordPress
$received_ts = 1754011429;
$secret_key = 'HG_RO_WP_SSO_2024_SecureKey_xyz789ABC';

$expected_token = hash('sha256', $received_nrp . $received_nama . $received_ts . $secret_key);

// Bandingkan token
if ($received_token === $expected_token) {
    return "TOKEN VALID";
} else {
    return "TOKEN INVALID";
}
```

### Penjelasan untuk Tim Host WordPress

**Yang Perlu Tim WordPress Pahami:**

1. **Secret Key Harus Sama di Kedua Sisi**
   ```
   WordPress: $secret_key = 'HG_RO_WP_SSO_2024_SecureKey_xyz789ABC';
   HG RO:     SSO_WORDPRESS_SECRET_KEY=HG_RO_WP_SSO_2024_SecureKey_xyz789ABC
   ```

2. **Cara Membuat Token** (di WordPress):
   ```php
   $token = hash('sha256', $nrp . $nama . $timestamp . $secret_key);
   ```

3. **Cara Memvalidasi Token** (di WordPress):
   ```php
   // Terima data dari HG RO
   $received_token = $_POST['token'];
   $received_nrp = $_POST['nrp'];
   $received_ts = $_POST['ts'];
   $received_secret = $_POST['secret_key'];
   
   // Cek secret key dulu
   if ($received_secret !== $our_secret_key) {
       return "INVALID SECRET KEY";
   }
   
   // Ambil nama user dari database
   $user_data = get_user_by_nrp($received_nrp);
   $nama = $user_data['nama'];
   
   // Recreate token
   $expected_token = hash('sha256', $received_nrp . $nama . $received_ts . $our_secret_key);
   
   // Bandingkan
   if ($received_token === $expected_token) {
       return "VALID";
   } else {
       return "INVALID";
   }
   ```

### Mengapa Secret Key Penting?

1. **Keamanan**: Tanpa secret key yang tepat, tidak bisa buat token valid
2. **Validasi**: HG RO bisa pastikan token benar-benar dari WordPress
3. **Integritas**: Mencegah orang lain membuat token palsu

**Analogi Sederhana:**
Secret key seperti "kata sandi" antara WordPress dan HG RO. Hanya yang tahu kata sandi ini yang bisa membuat dan memvalidasi token SSO
