Separate session lifetime for each user
In my Laravel application, each user (User model) belongs to an organization (Organization model). I need to be able to configure the session lifetime (session.lifetime config value) separately for each user based on the organization. (Not logged in users will still use the default session.lifetime config value.)
I am using Laravel version 8.52.0 using PHP version 7.4.16. I am not using any packages related to session. Session driver is redis.
The session lifetime value is stored in the database -> organizations table -> session_lifetime column (integer). Organization's admin users are able to change it in the admin page.
I have created a CustomSessionLifetime middleware:
public function handle(Request $request, Closure $next)
{
$user = auth()->user();
if ($user !== null)
{
$lifetime = $user->organization->session_lifetime;
config()->set('session.lifetime', $lifetime);
}
return $next($request);
}
Now I have kind of a circular problem:
1) If I set the CustomSessionLifetime middleware to run BEFORE StartSession middleware, like this:
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
//...
\App\Http\Middleware\CustomSessionLifetime::class,
\Illuminate\Session\Middleware\StartSession::class,
//...
],
then I am unable to get the user (and thus the organization or the session_lifetime attribute value) using auth()->user() function because the session is not yet started.
2) If I set the CustomSessionLifetime middleware to run AFTER StartSession middleware, like this:
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
//...
\Illuminate\Session\Middleware\StartSession::class,
\App\Http\Middleware\CustomSessionLifetime::class,
//...
],
then I am unable to configure the session.lifetime config value because the session is already started and the old value has been used there.
Another solution that came to my mind is using a different kind of custom middleware after the StartSession middleware which manually destroys and regenerates the session if time_now - last_activity_time > session_lifetime. Unfortunately I am unable to retrieve the last_activity_time value because I am using Redis as session handler which uses the cache session handler where the remaining time is simply the cache TTL (so it's not saved anywhere to be able to retrieve it). I could also use the custom middleware to save the last_activity_time in each request but this means saving new session data into Redis after every single request for every single user. This would be a huge performance hit when there are thousands or tens of thousands of active users simultaneously.
I was kind of surprised that Laravel didn't have a native way to achieve something like this as I think it seems pretty standard to want to customize the session lifetime based on user somehow.
How could I make this work?
Please or to participate in this conversation.