finmetrik/console-sso-sdk

PHP SDK for Console SSO Hub integration - Single Sign-On client library

Installs: 522

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/finmetrik/console-sso-sdk

1.0.1 2025-12-05 15:03 UTC

This package is auto-updated.

Last update: 2025-12-05 15:05:46 UTC


README

Latest Version on Packagist Total Downloads License

PHP SDK for integrating with the Console SSO Hub. Enables Single Sign-On (SSO) authentication for your PHP applications.

Requirements

  • PHP 8.1 or higher
  • Composer
  • GuzzleHTTP 7.0+

Installation

composer require finmetrik/console-sso-sdk

Configuration

Laravel

The package auto-discovers in Laravel. Publish the config file:

php artisan vendor:publish --tag=sso-config

Add to your .env:

SSO_HUB_URL=https://console.example.com
SSO_APP_KEY=your-app-key
SSO_APP_SECRET=your-app-secret
SSO_CALLBACK_URL=/sso/callback
SSO_VERIFY_SSL=true

Other PHP Frameworks

use Finmetrik\ConsoleSso\SsoClient;

$sso = new SsoClient([
    'hub_url' => 'https://console.example.com',
    'app_key' => 'your-app-key',
    'app_secret' => 'your-app-secret',
    'verify_ssl' => true,
]);

Quick Start (Recommended Flow)

The recommended flow is to redirect users to Console's /sso/authorize endpoint, which handles the login UI and redirects back with a token.

1. Redirect to Console SSO

// In your controller
public function redirectToSso()
{
    $hubUrl = config('sso.hub_url');
    $appKey = config('sso.app_key');
    $callbackUrl = urlencode(route('sso.callback'));
    
    // Redirect to Console's authorization endpoint
    return redirect("{$hubUrl}/sso/authorize?app_key={$appKey}&redirect_uri={$callbackUrl}");
}

2. Handle Callback

use Finmetrik\ConsoleSso\Laravel\Facades\Sso;
use Finmetrik\ConsoleSso\Exceptions\TokenExpiredException;
use Finmetrik\ConsoleSso\Exceptions\CompanyNotSubscribedException;

public function callback(Request $request)
{
    // Check for errors from Console
    if ($request->has('error')) {
        return redirect('/login')->withErrors([
            'sso' => $request->error_description ?? 'Authentication failed'
        ]);
    }
    
    $token = $request->query('token');
    
    if (!$token) {
        return redirect('/login')->withErrors(['sso' => 'No token received']);
    }
    
    try {
        // Verify token - only sends the token, Console returns user data
        $result = Sso::verifyToken($token);
        
        // $result contains:
        // - user: ['id', 'email', 'name', 'role']
        // - company: ['id', 'uuid', 'name']
        // - session: ['id', 'expires_at']
        
        // Create or update local user
        $user = User::updateOrCreate(
            ['email' => $result['user']['email']],
            ['name' => $result['user']['name']]
        );
        
        Auth::login($user, true);
        
        // Store SSO session for later validation
        session(['sso_session_id' => $result['session']['id']]);
        
        return redirect('/dashboard');
        
    } catch (TokenExpiredException $e) {
        return redirect('/login')->withErrors(['sso' => 'Login link expired']);
    } catch (CompanyNotSubscribedException $e) {
        return redirect('/login')->withErrors(['sso' => 'Access denied']);
    } catch (\Exception $e) {
        Log::error('SSO Error', ['message' => $e->getMessage()]);
        return redirect('/login')->withErrors(['sso' => 'Authentication failed']);
    }
}

3. Logout

public function logout(Request $request)
{
    $sessionId = session('sso_session_id');
    
    if ($sessionId) {
        try {
            Sso::destroySession($sessionId);
        } catch (\Exception $e) {
            // Log but don't fail
            Log::warning('SSO session destroy failed', ['error' => $e->getMessage()]);
        }
    }
    
    Auth::logout();
    $request->session()->invalidate();
    $request->session()->regenerateToken();
    
    return redirect('/login');
}

SSO Flow Diagram

┌─────────────────┐                  ┌─────────────────┐
│   Your App      │                  │    Console      │
│  (Client App)   │                  │   (SSO Hub)     │
└────────┬────────┘                  └────────┬────────┘
         │                                    │
         │  1. User clicks "Login with SSO"  │
         │                                    │
         │  2. Redirect to Console:           │
         │     /sso/authorize?                │
         │       app_key=xxx&                 │
         │       redirect_uri=xxx             │
         │ ─────────────────────────────────> │
         │                                    │
         │                    3. User logs in │
         │                       (if needed)  │
         │                                    │
         │  4. Redirect back with token:      │
         │     /sso/callback?token=abc123     │
         │ <───────────────────────────────── │
         │                                    │
         │  5. Verify token via API:          │
         │     POST /api/hub/sso/verify       │
         │     Body: { "token": "abc123" }    │
         │ ─────────────────────────────────> │
         │                                    │
         │  6. Return user data + session     │
         │ <───────────────────────────────── │
         │                                    │
         │  7. Create local user & login      │
         │                                    │
         ▼                                    ▼
    User is now logged in!

Signature Algorithm

The SDK automatically signs all API requests using HMAC-SHA256:

signature = HMAC-SHA256(app_key + timestamp + request_body, app_secret)

Headers sent with each request:

  • X-App-Key: Your application key
  • X-Timestamp: Unix timestamp
  • X-Signature: HMAC signature

Session Validation Middleware

Laravel

Register the middleware:

// app/Http/Kernel.php (Laravel 10 and below)
protected $middlewareAliases = [
    'sso.session' => \Finmetrik\ConsoleSso\Laravel\Middleware\ValidateSsoSession::class,
];

// bootstrap/app.php (Laravel 11+)
->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'sso.session' => \Finmetrik\ConsoleSso\Laravel\Middleware\ValidateSsoSession::class,
    ]);
})

Apply to routes:

Route::middleware(['auth', 'sso.session'])->group(function () {
    Route::get('/dashboard', [DashboardController::class, 'index']);
});

Manual Validation

try {
    $session = Sso::validateSession($sessionId);
    // Session is valid
} catch (SessionExpiredException $e) {
    Auth::logout();
    return redirect('/login');
}

API Reference

SsoClient Methods

Method Description
bootstrap() Fetch app configuration from SSO Hub
verifyToken(string $token) Verify SSO token and get user data
validateSession(string $sessionId) Check if session is valid
refreshSession(string $sessionId) Extend session expiry
destroySession(string $sessionId) Logout / destroy session
isConfigured() Check if client is configured
getAppInfo() Get app information

Exceptions

Exception When Thrown
ConfigurationException Missing or invalid configuration
ApiException API request failed
TokenExpiredException SSO token has expired
TokenUsedException Token already consumed
SessionExpiredException Session has expired
CompanyNotSubscribedException Company not subscribed to app
UserNotFoundException User not found in company

Error Handling

use Finmetrik\ConsoleSso\Exceptions\{
    TokenExpiredException,
    TokenUsedException,
    SessionExpiredException,
    CompanyNotSubscribedException,
    UserNotFoundException,
    ApiException
};

try {
    $result = Sso::verifyToken($token);
} catch (TokenExpiredException $e) {
    // Token expired (5 min validity), redirect to login
} catch (TokenUsedException $e) {
    // Token already used, possible replay attack
} catch (CompanyNotSubscribedException $e) {
    // Company doesn't have access to this app
} catch (UserNotFoundException $e) {
    // User not found in company
} catch (ApiException $e) {
    // General API error
    Log::error('SSO Error: ' . $e->getMessage());
}

Debugging

Enable debug mode by passing a PSR-3 logger:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('sso');
$logger->pushHandler(new StreamHandler('path/to/sso.log', Logger::DEBUG));

$sso = new SsoClient([
    'hub_url' => '...',
    'app_key' => '...',
    'app_secret' => '...',
    'logger' => $logger,
]);

Security

  • Never expose app_secret in client-side code
  • Always use HTTPS in production
  • Store session IDs server-side only
  • Implement CSRF protection on callback endpoints
  • Validate the state parameter if using one

Changelog

v1.0.1

  • Fixed token verification to only require token parameter
  • Console now returns user data from token record
  • Updated documentation with correct flow

v1.0.0

  • Initial release

License

MIT License. See LICENSE for details.

Support

  • Documentation: See docs/plan/ in Console repository
  • Issues: Contact your Console administrator