Buku Tamu SSO

PHP (Laravel)

Contoh integrasi OAuth dengan Laravel.

<?php
// routes/web.php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\OAuthController;

Route::get('/login', [OAuthController::class, 'login'])->name('oauth.login');
Route::get('/callback', [OAuthController::class, 'callback'])->name('oauth.callback');
Route::post('/refresh', [OAuthController::class, 'refresh'])->name('oauth.refresh');
<?php
// app/Http/Controllers/OAuthController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Session;

class OAuthController extends Controller
{
    // Konfigurasi
    private string $clientId = 'YOUR_CLIENT_ID';
    private string $clientSecret = 'YOUR_CLIENT_SECRET';
    private string $redirectUri = 'http://localhost:8000/callback';
    private string $authServerUrl; // Origin (tanpa /api/auth)
    private string $issuer; // Issuer OIDC (.../api/auth)
    private array $scopes = ['openid', 'profile', 'email', 'role', 'organization'];

    public function __construct()
    {
        $this->authServerUrl = 'https://bukutamu.tabalongkab.go.id';
        $this->issuer = 'https://bukutamu.tabalongkab.go.id/api/auth';
    }

    /**
     * Generate code verifier untuk PKCE
     */
    private function generateCodeVerifier(): string
    {
        return Str::random(64);
    }

    /**
     * Generate code challenge dari code verifier (S256)
     */
    private function generateCodeChallenge(string $codeVerifier): string
    {
        $hash = hash('sha256', $codeVerifier, true);
        return rtrim(strtr(base64_encode($hash), '+/', '-_'), '=');
    }

    /**
     * Mulai OAuth flow
     */
    public function login()
    {
        // Generate PKCE values
        $codeVerifier = $this->generateCodeVerifier();
        $codeChallenge = $this->generateCodeChallenge($codeVerifier);
        $state = Str::random(32);

        // Simpan untuk verifikasi nanti
        Session::put('oauth_state', $state);
        Session::put('code_verifier', $codeVerifier);

        // Buat authorization URL
        $authParams = http_build_query([
            'client_id' => $this->clientId,
            'redirect_uri' => $this->redirectUri,
            'response_type' => 'code',
            'scope' => implode(' ', $this->scopes),
            'state' => $state,
            'code_challenge' => $codeChallenge,
            'code_challenge_method' => 'S256',
        ]);

        $authUrl = "{$this->authServerUrl}/api/auth/oauth2/authorize?{$authParams}";

        // Redirect user ke SSO Tabalong
        return redirect($authUrl);
    }

    /**
     * Handle OAuth callback
     */
    public function callback(Request $request)
    {
        // Handle error dari OAuth server
        if ($request->has('error')) {
            return response()->json([
                'error' => $request->get('error'),
                'error_description' => $request->get('error_description'),
            ], 400);
        }

        $code = $request->get('code');
        $state = $request->get('state');

        // Verifikasi state
        if ($state !== Session::get('oauth_state')) {
            return response()->json(['error' => 'Invalid state parameter'], 400);
        }

        $codeVerifier = Session::get('code_verifier');

        // Bersihkan session
        Session::forget(['oauth_state', 'code_verifier']);

        // Tukar code dengan token
        $tokenResponse = Http::asForm()->post(
            "{$this->authServerUrl}/api/auth/oauth2/token",
            [
                'grant_type' => 'authorization_code',
                'code' => $code,
                'redirect_uri' => $this->redirectUri,
                'client_id' => $this->clientId,
                'client_secret' => $this->clientSecret,
                'code_verifier' => $codeVerifier,
            ]
        );

        if (!$tokenResponse->successful()) {
            return response()->json($tokenResponse->json(), 400);
        }

        $tokens = $tokenResponse->json();

        // Ambil user info
        $userInfoResponse = Http::withToken($tokens['access_token'])
            ->get("{$this->authServerUrl}/api/auth/oauth2/userinfo");

        $userInfo = $userInfoResponse->json();

        // Simpan di session
        Session::put('user', $userInfo);
        Session::put('tokens', $tokens);

        return response()->json([
            'tokens' => $tokens,
            'userinfo' => $userInfo,
        ]);
    }

    /**
     * Refresh access token
     */
    public function refresh(Request $request)
    {
        $refreshToken = $request->input('refresh_token');

        $response = Http::asForm()->post(
            "{$this->authServerUrl}/api/auth/oauth2/token",
            [
                'grant_type' => 'refresh_token',
                'refresh_token' => $refreshToken,
                'client_id' => $this->clientId,
                'client_secret' => $this->clientSecret,
            ]
        );

        return response()->json($response->json());
    }
}