user(); if ($user) { Session::put([ 'activeProfileType' => \App\Models\User::class, 'activeProfileId' => $user->id, 'activeProfileName' => $user->name, 'activeProfilePhoto' => $user->profile_photo_path, ]); } } $lastActivity = Session::get('last_activity'); // If last_activity is not set, initialize it and continue (first request after login) if (!$lastActivity) { Session::put('last_activity', now()); return $next($request); } // Check base session timeout first (this should never exceed SESSION_LIFETIME) // This prevents profile-specific timeouts from keeping sessions alive beyond the base session lifetime $baseSessionLifetime = Config::get('session.lifetime', 120); // minutes $minutesSinceActivity = now()->diffInMinutes($lastActivity); // If base session has expired, force logout regardless of profile type if ($minutesSinceActivity >= $baseSessionLifetime) { $user = Auth::guard('web')->user(); Auth::guard('web')->logout(); Session::invalidate(); Session::regenerateToken(); // For AJAX requests, return a JSON response indicating logout if ($request->expectsJson() || $request->ajax()) { return response()->json([ 'message' => __('Your session timed out due to inactivity. Please log in again.'), 'action' => 'logout', 'redirect_url' => LaravelLocalization::localizeUrl('/login') ], 419); // 419 Authentication Timeout } else { // For standard browser requests, redirect to login $loginUrl = LaravelLocalization::localizeUrl('/login'); return redirect()->to($loginUrl) ->with('warning', __('Your session timed out due to inactivity. Please log in again.')); } } // Get the specific timeout for the current profile type, or use the default of 120 min. $configuredTimeout = timebank_config('profile_timeouts.' . $activeProfileType, timebank_config('profile_timeout_default', 120)); // Profile-specific timeout cannot exceed base session lifetime // This ensures elevated profiles timeout at or before the base session expiration $timeoutMinutes = min($configuredTimeout, $baseSessionLifetime); // Log when timeout is being capped for debugging purposes if ($configuredTimeout > $baseSessionLifetime) { \Log::info('Profile timeout capped by SESSION_LIFETIME', [ 'profile_type' => class_basename($activeProfileType), 'configured_timeout' => $configuredTimeout, 'session_lifetime' => $baseSessionLifetime, 'effective_timeout' => $timeoutMinutes, ]); } // Check if the timestamp exists and if the inactivity period has passed if ($minutesSinceActivity >= $timeoutMinutes) { $user = Auth::guard('web')->user(); // Check if the current active profile is already the User profile if ($activeProfileType === \App\Models\User::class) { // If the active profile is User and their session expires, log them out Auth::guard('web')->logout(); Session::invalidate(); Session::regenerateToken(); // For AJAX requests, return a JSON response indicating logout if ($request->expectsJson() || $request->ajax()) { return response()->json([ 'message' => __('Your session timed out due to inactivity. Please log in again.'), 'action' => 'logout', // Indicate a full logout 'redirect_url' => LaravelLocalization::localizeUrl('/login') // Provide login URL ], 419); // 419 Authentication Timeout } else { // For standard browser requests, redirect to login $loginUrl = LaravelLocalization::localizeUrl('/login'); return redirect()->to($loginUrl) ->with('warning', __('Your session timed out due to inactivity. Please log in again.')); } } else { // If the active profile is an elevated profile (Bank, Admin, etc.), switch back to User profile Session::put([ 'activeProfileType' => \App\Models\User::class, 'activeProfileId' => $user->id, 'activeProfileName' => $user->name, 'activeProfilePhoto' => $user->profile_photo_path, 'profile-switched-notification' => true, ]); session(['notification.alert' => 'Your previous profile session timed out due to inactivity.']); // Will become a translation key in notification component Session::forget('last_activity'); // Clear the timestamp event(new \App\Events\ProfileSwitchEvent($user)); // Check if the request expects JSON (common for AJAX) or is an AJAX request if ($request->expectsJson() || $request->ajax()) { session(['notification.alert' => 'Your previous profile session timed out due to inactivity.']); // Will become a translation key in notification component // Get the user's locale from the session (set by localization middleware) $userLocale = Session::get('locale', config('app.fallback_locale')); // Use LaravelLocalization to get the full, localized URL $redirectUrl = LaravelLocalization::getURLFromRouteNameTranslated($userLocale, 'routes.main'); Session::save(); // Return a JSON response indicating timeout, use 419 status code return response()->json([ 'message' => __('Your previous profile session timed out due to inactivity.'), 'action' => 'redirect', // Change action name to 'redirect' 'redirect_url' => $redirectUrl // <-- Add URL to payload ], 419); // 419 Authentication Timeout } else { // For standard browser requests, perform the redirect with flash message $mainUrl = LaravelLocalization::localizeUrl('/main-page'); return redirect()->to($mainUrl) ->with('warning', __('Your previous profile session timed out due to inactivity.')); } } } // Update the activity timestamp on relevant requests // Exclude background heartbeats but allow user-initiated Livewire interactions $isLivewireUpdate = $request->is(['*/livewire/update', 'livewire/update']); $isUserInteraction = $isLivewireUpdate && $request->has('components'); if (!$request->is(['api/messenger/heartbeat']) && (!$isLivewireUpdate || $isUserInteraction)) { Session::put('last_activity', now()); } return $next($request); // Ensure the request is passed to the next middleware } }