Reputation: 49
I am trying to set a custom message when a user session has timed out. I managed to setup the timeout rerouting, but I struggle to include a message to notify the user. Here's part of the code that I believe is relevant:
composer.json
"require": {
"php": "^8.2",
"laravel/framework": "^11.9",
"laravel/tinker": "^2.9",
"laravel/ui": "^4.5"
},
"require-dev": {
"laravel/breeze": "^2.1"
}
login.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="{{ mix('style.css') }}">
</head>
<body>
<section>
<div id="form-container">
<form action="{{ route('login.submit') }}" method="POST">
...
</form>
</div>
</section>
@if(session('error'))
<div class="alert alert-danger">
{{ session('error') }}
</div>
@else
<p>no problem here.</p>
@endif
</body>
</html>
CheckSessionTimeout.php (middleware)
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
class CheckSessionTimeout
{
public function handle(Request $request, Closure $next): Response
{
if (Auth::check()) {
$lastActivityTime = $request->session()->get('lastActivityTime', time());
$sessionTimeout = config('session.lifetime') * 60;
if (time() - $lastActivityTime > $sessionTimeout) {
Auth::guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->route('login')->with('error', 'Your session has expired. Please log in again.');
}
$request->session()->put('lastActivityTime', time());
}
return $next($request);
}
}
web.php (routing)
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\LoginController;
use App\Http\Controllers\RosterController;
use App\Http\Controllers\Auth\AuthenticatedSessionController;
use App\Http\Middleware\CheckSessionTimeout;
require __DIR__.'/auth.php';
Route::get('/login', function () {
return view('login');
})->name('login');
Route::post('/login', [LoginController::class, 'login']
)->name('login.submit');
Route::middleware([CheckSessionTimeout::class])->group(function () {
...
Route::middleware('auth')->group(function () {
Route::post('/logout', [AuthenticatedSessionController::class, 'destroy']
)->name('logout');
});
});
I would like to briefly address my ideal output and current outcome:
Ideal: After a user session timed out, the next request will always go to login.php view, with extra message that informs the user their session has timed out.
Outcome: The user did get redirect to login.php, but the message never shows.
I tried working with ChatGPT before asking this, all the suggestion are:
Session Lifetime Configuration: I set a fixed duration and I can consistently trigger timeout.
Middleware Execution: I reviewed my middleware code over and over again, and approved by ChatGPT.
Session Flash Mechanism: It kepts suggesting between ->flash() and ->with(), I am currently using the latter
Middleware Order: I reviewed my code over and over again as well, and no apparent issues.
Upvotes: 1
Views: 204
Reputation: 49
After debugging every single step and study more on Laravel functions, I learnt that the behavior when a session lifetime runs out, the system automatically logout and clears session data, leaving nothing for my middleware to catch.
Here's the configs about session lifetime:
session.php
<?php
use Illuminate\Support\Str;
return [
'lifetime' => env('SESSION_LIFETIME', 120),
'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false)
];
The only meaningful change compared to my question code is this single line:
CheckSessionTimeout.php
$sessionTimeout = config('session.lifetime') * 60 - 1;
I let my middleware take the initiative by running the session check 1 second before the session lifetime runs out, and my custom message finally displays in my view.
I hope whoever runs into the same trouble as me can resolve their situation as well with this reference.
Upvotes: 1