diff --git a/app/Http/Controllers/Auth/SsoLoginController.php b/app/Http/Controllers/Auth/SsoLoginController.php index fb5fc1e..0da2a5a 100644 --- a/app/Http/Controllers/Auth/SsoLoginController.php +++ b/app/Http/Controllers/Auth/SsoLoginController.php @@ -138,6 +138,18 @@ class SsoLoginController extends Controller return redirect()->away($this->defaultSignedOutUrl()); } + /** Platform session ended — clear this app and offer silent sign-in again. */ + public function platformSignedOut(Request $request): RedirectResponse + { + Auth::logout(); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + return redirect()->route('sso.connect', [ + 'redirect' => (string) $request->query('redirect', ''), + ]); + } + public function logoutBridge(Request $request): View { $return = $this->safeReturnUrl((string) $request->query('return', '')); diff --git a/app/Http/Middleware/EnsurePlatformSession.php b/app/Http/Middleware/EnsurePlatformSession.php new file mode 100644 index 0000000..db642f5 --- /dev/null +++ b/app/Http/Middleware/EnsurePlatformSession.php @@ -0,0 +1,58 @@ +headers->get('Cookie', ''); + if ($cookieHeader === '') { + return $this->clearAppSession($request); + } + + try { + $response = Http::withHeaders(['Cookie' => $cookieHeader]) + ->timeout(3) + ->get('https://'.$authDomain.'/sso/ping'); + } catch (\Throwable) { + return $next($request); + } + + if ($response->status() === 401) { + return $this->clearAppSession($request); + } + + return $next($request); + } + + private function clearAppSession(Request $request): Response + { + Auth::logout(); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + return redirect()->route('sso.connect', [ + 'redirect' => $request->fullUrl(), + ]); + } +} diff --git a/bootstrap/app.php b/bootstrap/app.php index 0dffcc8..6504353 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -19,6 +19,9 @@ return Application::configure(basePath: dirname(__DIR__)) $middleware->web(append: [ \App\Http\Middleware\SetActingAccount::class, ]); + $middleware->alias([ + 'platform.session' => \App\Http\Middleware\EnsurePlatformSession::class, + ]); // External registrar webhook posts have no CSRF token. $middleware->validateCsrfTokens(except: [ diff --git a/resources/views/partials/sso-keepalive.blade.php b/resources/views/partials/sso-keepalive.blade.php index ecd5d4a..2d297c5 100644 --- a/resources/views/partials/sso-keepalive.blade.php +++ b/resources/views/partials/sso-keepalive.blade.php @@ -1,4 +1,21 @@ @if (auth()->check()) - {{-- Same-site iframe keeps the shared auth.ladill.com session warm while using this app. --}} - + @php + $authPing = 'https://'.config('app.auth_domain').'/sso/ping'; + $platformSignedOutUrl = route('sso.platform-signed-out', ['redirect' => url()->current()]); + @endphp + @endif diff --git a/routes/web.php b/routes/web.php index 570d2bf..2b05f30 100644 --- a/routes/web.php +++ b/routes/web.php @@ -28,9 +28,10 @@ Route::get('/sso/callback', [SsoLoginController::class, 'callback'])->name('sso. Route::post('/logout', [SsoLoginController::class, 'logout'])->name('logout'); Route::get('/sso/logout-bridge', [SsoLoginController::class, 'logoutBridge'])->name('sso.logout-bridge'); Route::get('/sso/logout-frontchannel', [SsoLoginController::class, 'frontchannelLogout'])->name('sso.logout-frontchannel'); +Route::get('/sso/platform-signed-out', [SsoLoginController::class, 'platformSignedOut'])->name('sso.platform-signed-out'); Route::get('/signed-out', fn () => auth()->check() ? redirect()->route('hosting.dashboard') : view('hosting.signed-out'))->name('hosting.signed-out'); -Route::middleware(['auth'])->group(function () use ($serversApp) { +Route::middleware(['auth', 'platform.session'])->group(function () use ($serversApp) { Route::get('/notifications', [NotificationController::class, 'index'])->name('notifications.index'); Route::get('/notifications/unread', [NotificationController::class, 'unread'])->name('notifications.unread'); Route::post('/notifications/{id}/read', [NotificationController::class, 'markAsRead'])->name('notifications.mark-read');