Derrick
Derrick

Reputation: 49

Laravel 11.9 Flash Sessioned Data Not Passing Message

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

Answers (1)

Derrick
Derrick

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

Related Questions