How to log users off automatically after a period of inactivity? How to log users off automatically after a period of inactivity? symfony symfony

How to log users off automatically after a period of inactivity?


You have to implement it with a kernel listener, this is the way I solve it:

Listener src/Comakai/MyBundle/Handler/SessionIdleHandler.php

namespace Comakai\MyBundle\Handler;use Symfony\Component\HttpKernel\HttpKernelInterface;use Symfony\Component\HttpKernel\Event\GetResponseEvent;use Symfony\Component\HttpFoundation\Session\SessionInterface;use Symfony\Component\Routing\RouterInterface;use Symfony\Component\HttpFoundation\RedirectResponse;use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;class SessionIdleHandler{    protected $session;    protected $securityToken;    protected $router;    protected $maxIdleTime;    public function __construct(SessionInterface $session, TokenStorageInterface $securityToken, RouterInterface $router, $maxIdleTime = 0)    {        $this->session = $session;        $this->securityToken = $securityToken;        $this->router = $router;        $this->maxIdleTime = $maxIdleTime;    }    public function onKernelRequest(GetResponseEvent $event)    {        if (HttpKernelInterface::MASTER_REQUEST != $event->getRequestType()) {            return;        }        if ($this->maxIdleTime > 0) {            $this->session->start();            $lapse = time() - $this->session->getMetadataBag()->getLastUsed();            if ($lapse > $this->maxIdleTime) {                $this->securityToken->setToken(null);                $this->session->getFlashBag()->set('info', 'You have been logged out due to inactivity.');                // Change the route if you are not using FOSUserBundle.                $event->setResponse(new RedirectResponse($this->router->generate('fos_user_security_login')));            }        }    }}

Config src/Comakai/MyBundle/Resources/config/services.yml (Comakai/MyBundle/DependencyInjection/MyBundleExtension.php)

services:    my.handler.session_idle:        class: Comakai\MyBundle\Handler\SessionIdleHandler        arguments: ["@session", "@security.context", "@router", %session_max_idle_time%]        tags:            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }

Now you can set the session_max_idle_time in parameters.yml to 30 * 60 = 1800 seconds (or just hardcode the value wherever you want):

Parameters app/config/parameters.yml

parameters:    ...    session_max_idle_time: 1800


The following setting will log out users that are inactive for more than 30minutes. If a request is made every 29minutes, they will never be logged out. Please note that this is not easy to test in an local environment as the garbage collector is only called from your request thus the gc_maxlifetime is never reached!

#app/config/config.ymlsession:    cookie_lifetime: 86400    gc_maxlifetime: 1800

You can test this if you open more browsers/sessions and use the following config:

#app/config/config.ymlsession:    cookie_lifetime: 86400    gc_maxlifetime: 1800    gc_probability: 1    gc_divisor: 1

Hope that helps!

Please note, adding:

 session:    gc_probability: 1    gc_divisor: 1

Is only meant for testing the garbage collector on a local environment where there are no other requests that cause the garbage collector to remove your session. Making the garbage collector run on every request is not meant (or necessary) on a productive environment!


In case anybody wants to implement this in Symfony 4, I've updated the answer @coma gave since security.context is depreciated, parameters.yml is now just part of app/config/service.yaml and you can just inject the other variables for the contructor. It's basically the same answer though, just tweaked to work for Symfony 4:

Listener src/Security/SessionIdleHandler.php (or anywhere, it's mapped in the event listener below)

<?phpnamespace App\Security;use Symfony\Component\HttpKernel\HttpKernelInterface;use Symfony\Component\HttpKernel\Event\GetResponseEvent;use Symfony\Component\HttpFoundation\Session\SessionInterface;use Symfony\Component\Routing\RouterInterface;use Symfony\Component\HttpFoundation\RedirectResponse;use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;class SessionIdleHandler{    protected $session;    protected $securityToken;    protected $router;    protected $maxIdleTime;    public function __construct($maxIdleTime, SessionInterface $session, TokenStorageInterface $securityToken, RouterInterface $router)    {        $this->session = $session;        $this->securityToken = $securityToken;        $this->router = $router;        $this->maxIdleTime = $maxIdleTime;    }    public function onKernelRequest(GetResponseEvent $event)    {        if (HttpKernelInterface::MASTER_REQUEST != $event->getRequestType()) {            return;        }        if ($this->maxIdleTime > 0) {            $this->session->start();            $lapse = time() - $this->session->getMetadataBag()->getLastUsed();            if ($lapse > $this->maxIdleTime) {                $this->securityToken->setToken(null);                $this->session->getFlashBag()->set('info', 'You have been logged out due to inactivity.');                // logout is defined in security.yaml.  See 'Logging Out' section here:                // https://symfony.com/doc/4.1/security.html                $event->setResponse(new RedirectResponse($this->router->generate(logout)));            }        }    }}

Parameters app/config/service.yaml

parameters:    ...    session_max_idle_time: 600 // set to whatever value you want in seconds

Kernel Event Listener app/config/service.yaml

services:    ...    App.Handler.SessionIdle:        class: App\Security\SessionIdleHandler        arguments: ['%session_max_idle_time%']        tags: [{ name: kernel.event_listener, event: kernel.request }]