This guide explains how to integrate Single Sign-On (SSO) between your main website and the Central Tickets system, allowing users to seamlessly authenticate from the logout landing page.
When a user clicks "Sign In with [Your Company]" on the logout landing page:
https://yourwebsite.com/ticket-ssoThe logout page passes these URL parameters to your SSO endpoint:
redirect_url: Where to send the user after authentication (e.g., https://ticket.yourcompany.com/yourcompany/dashboard)callback_api: The API endpoint to call for authentication (e.g., https://tickets.flare99.com/api/auth/redirect/yourcompany)tenant: Your tenant slug (e.g., yourcompany)Create a file at https://yourwebsite.com/ticket-sso.php:
<?php
// Check if user is logged in
session_start();
if (!isset($_SESSION['user_id'])) {
// Redirect to login with return URL
$returnUrl = urlencode($_SERVER['REQUEST_URI']);
header("Location: /login?return=" . $returnUrl);
exit;
}
// Get user data from your session/database
$user = getUserById($_SESSION['user_id']); // Your user retrieval function
// Get parameters
$redirectUrl = $_GET['redirect_url'] ?? '';
$callbackApi = $_GET['callback_api'] ?? '';
$tenantSlug = $_GET['tenant'] ?? '';
// Validate parameters
if (empty($redirectUrl) || empty($callbackApi)) {
die('Invalid SSO request');
}
// Call ticket system API
$userData = [
'email' => $user['email'],
'name' => $user['name'],
'redirect_url' => $redirectUrl
];
$ch = curl_init($callbackApi);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json'
],
CURLOPT_POSTFIELDS => json_encode($userData),
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_HEADER => true
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// Extract Location header from response
if ($httpCode === 302) {
preg_match('/Location: (.+)/', $response, $matches);
if (isset($matches[1])) {
$redirectTo = trim($matches[1]);
curl_close($ch);
header("Location: " . $redirectTo);
exit;
}
}
curl_close($ch);
die('Authentication failed');
?>
Route (routes/web.php):
Route::get('/ticket-sso', [SSOController::class, 'handleTicketSSO'])
->middleware('auth')
->name('ticket.sso');
Controller (app/Http/Controllers/SSOController.php):
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Auth;
class SSOController extends Controller
{
public function handleTicketSSO(Request $request)
{
// Validate user is logged in
if (!Auth::check()) {
return redirect('/login?return=' . urlencode($request->fullUrl()));
}
// Get parameters
$redirectUrl = $request->query('redirect_url');
$callbackApi = $request->query('callback_api');
$tenantSlug = $request->query('tenant');
// Validate parameters
if (!$redirectUrl || !$callbackApi || !$tenantSlug) {
abort(400, 'Invalid SSO request parameters');
}
// Get authenticated user
$user = Auth::user();
// Call ticket system API
try {
$response = Http::withHeaders([
'Accept' => 'application/json',
'Content-Type' => 'application/json',
])->post($callbackApi, [
'email' => $user->email,
'name' => $user->name,
'redirect_url' => $redirectUrl,
]);
// Check if response is a redirect
if ($response->redirect()) {
return redirect($response->header('Location'));
}
// If JSON response with redirect_url
$data = $response->json();
if (isset($data['redirect_url'])) {
return redirect($data['redirect_url']);
}
abort(500, 'Invalid API response');
} catch (\Exception $e) {
\Log::error('Ticket SSO failed', [
'error' => $e->getMessage(),
'user_id' => $user->id,
]);
return view('ticket-sso-error', [
'message' => 'Unable to authenticate with ticket system. Please try again.'
]);
}
}
}
Create a page at https://yourwebsite.com/ticket-sso.html:
<!DOCTYPE html>
<html>
<head>
<title>Signing you in...</title>
<style>
body {
font-family: system-ui;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.container {
background: white;
padding: 2rem;
border-radius: 1rem;
text-align: center;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #667eea;
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 1s linear infinite;
margin: 0 auto 1rem;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="container">
<div class="spinner"></div>
<h1>Signing you in...</h1>
<p id="status">Authenticating with ticket system...</p>
</div>
<script>
// Get URL parameters
const urlParams = new URLSearchParams(window.location.search);
const redirectUrl = urlParams.get('redirect_url');
const callbackApi = urlParams.get('callback_api');
const tenantSlug = urlParams.get('tenant');
// Get user data from your authentication system
// This example assumes you have a function that returns logged-in user data
async function getUserData() {
// Replace with your actual user data retrieval
const response = await fetch('/api/user', {
credentials: 'include'
});
if (!response.ok) return null;
return await response.json();
}
async function authenticate() {
try {
// Get current user
const user = await getUserData();
if (!user) {
// Not logged in - redirect to login
window.location.href = '/login?return=' + encodeURIComponent(window.location.href);
return;
}
// Call ticket system API
const response = await fetch(callbackApi, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
email: user.email,
name: user.name,
redirect_url: redirectUrl
})
});
if (response.redirected) {
window.location.href = response.url;
} else {
const data = await response.json();
if (data.redirect_url) {
window.location.href = data.redirect_url;
} else {
throw new Error('No redirect URL received');
}
}
} catch (error) {
console.error('SSO Error:', error);
document.querySelector('.container').innerHTML = `
<h1 style="color: #e53e3e;">Authentication Failed</h1>
<p>Unable to sign you in. Please try again.</p>
<button onclick="history.back()" style="margin-top: 1rem; padding: 0.75rem 1.5rem; background: #667eea; color: white; border: none; border-radius: 0.5rem; cursor: pointer;">
Go Back
</button>
`;
}
}
// Start authentication
authenticate();
</script>
</body>
</html>
Test with logged-in user:
Test with logged-out user:
https://yourwebsite.com/ticket-sso)/api/auth/redirect/{tenant} is successfulFor additional help, refer to:
TENANT_INTEGRATION_GUIDE.md - Complete integration documentation/integration route - Integration hub with downloadable examplestenant-examples/ directory