44

i would like to do something like that in controller to log user out:

$user = $this->get('security.context')->getToken()->getUser();
$user->logOut();

7 Answers 7

80

Logout in Symfony2 is handled by so called logout handler which is just a lister that is executed when URL match pattern from security configuration, ie. if URL is let's say /logout then this listener is executed. There are two build-in logout handlers:

  1. CookieClearingLogoutHandler which simply clears all cookies.
  2. SessionLogoutHandler which invalidates the session

All you have to do is the very same the last one does. You can achieve it by simply calling:

Legacy Symfony

$this->get('security.context')->setToken(null);
$this->get('request')->getSession()->invalidate();

Symfony 2.6

$this->get('security.token_storage')->setToken(null);
$this->get('request')->getSession()->invalidate();

Warning

This will only work when remember me functionality is disabled. In other case, user will be logged in back again by means of a remember me cookie with the next request.

Please consider the extended solution if you are using remember me functionality: https://stackoverflow.com/a/28828377/1056679

7
  • 14
    You should also set the security token to null: $this->get('security.context')->setToken(null); $this->get('request')->getSession()->invalidate();
    – Bob F.
    Jun 23, 2012 at 16:08
  • 5
    There has to be some event that can be fired up, I can't believe they left us without a reliable way that preserves the locale and logs out the user. Jun 27, 2012 at 12:24
  • 4
    NOTE: Getting the Request object like this is deprecated since 2.4. Inject the Request into the Controller or user RequestStack: symfony.com/blog/new-in-symfony-2-4-the-request-stack
    – frank_neff
    Jan 17, 2014 at 10:55
  • The SessionLogoutHandler is accessible as a service: $this->get('security.logout.handler.session')->logout($request, $response, $token);
    – stixx
    Nov 10, 2014 at 15:07
  • I've tried this code with latest Symfony 2.6, but it has no effect. User is still logged in after page reload. Please advise. Thank you! Mar 2, 2015 at 16:10
11

Invalidating the user's session might cause some unwanted results. Symfony's firewall has a listener that always checks and refreshes the user's token. You could just do a redirect to the default logout route that you have specified in your firewall.yml (or security.yaml)

In Controller you can do this:

$this->redirect($this->generateUrl('your_logout_url'));

If you don't know the name of the logout route (your_logout_url), you can get it from the Symfony console by using this command:

app/console router:match /logout

Or newer Symfony versions:

bin/console router:match /logout

:)

2
  • 1
    I think this answer is the most simple and clean to do the job.
    – Hokusai
    Mar 15, 2016 at 16:16
  • 2
    If you want to force logout a malicious user, this will simply cause a redirect. The malicious user could simply ignore the 302 response, and continue doing their malicious activity. Say they are trying to change the password of a logged in user after successful session hijacking. 3 times entering wrong password should log them out, but here they can just ignore 302 and try anyway, unless you check the number of wrong attempts additionally. Bottom line: You can not enforce a logout like this.
    – Daidon
    Mar 15, 2020 at 1:34
9

We have to set user as an anonymous user when logging out. Then we can use
$token->getUser()->getRoles(); in controller or {% if is_granted('ROLE_USER') %} in the twig template.

use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
...
//$providerKey = $this->container->getParameter('fos_user.firewall_name');
$token = new AnonymousToken($providerKey, 'anon.');
$this->get('security.context')->setToken($token);
$this->get('request')->getSession()->invalidate();
1
  • This is especially useful if you want to prevent the user from being forced to reauthenticate after the logout! In a simple case, the provider key is just the name of your firewall (see security.yml).
    – ahuemmer
    Jun 23, 2015 at 8:11
2

If rememberme functionality is enabled for your site you should also clean rememberme cookie:

    $this->get('security.context')->setToken(null);
    $this->get('request')->getSession()->invalidate();

    $response = new RedirectResponse($this->generateUrl('dn_send_me_the_bundle_confirm', array(
                'token' => $token
                )));
    // Clearing the cookies.
    $cookieNames = [
        $this->container->getParameter('session.name'),
        $this->container->getParameter('session.remember_me.name'),
    ];
    foreach ($cookieNames as $cookieName) {
        $response->headers->clearCookie($cookieName);
    }
2
  • Don't know why it wasn't uped more, the clearcookie addition is interesting. (and works)
    – COil
    Oct 12, 2017 at 13:31
  • 1
    because it doesn't work. setting the token to null doesn't really unauthenticate the user
    – ma1069
    Nov 26, 2019 at 11:38
2

In Symfony 4/5 this is just enough to remove user:

    /**
     * @var TokenStorageInterface $token_storage
     */
    private TokenStorageInterface $token_storage;

    /**
     * Will force logout from system
     */
    public function logoutCurrentlyLoggedInUser()
    {
        $this->token_storage->setToken(null);
    }

Now You can create a method to use it later to check if user is logged in:

class Application extends AbstractController {...

    /**
     * Returns currently logged in user
     * @return object|UserInterface|null
     */
    public function getCurrentlyLoggedInUser()
    {
        return $this->getUser();
    }
0

In case you are using symfony 4.x (I haven't tested other versions, so it still might work), you may want to use the internal logout handler of symfony (highly recommended, as it will take care of everything for you in a clean way, cookies and all). You don't need to write too much code for that either, you can simply emulate a logout request:

... // Some code, that leads you to force logout the user 
// Emulating logout request
$logoutPath = $this->container->get('router')->generate('app_logout');
$logoutRequest = Request::create($logoutPath);
$logoutResponse = $this->container->get('http_kernel')->handle($logoutRequest);
// User is logged out now
... // Stuff to do after logging out, eg returning response

This will make symfony do the request response flow, thus it will call the logout handler internally. This method allows you to proceed to further custom code. Otherwise, if you invoked only the logout listener here, you would have to return the usual logout response, that now is in $logoutResponse. Optionally, if you want to return it, you would also simply:

return $logoutResponse;
0

The proposed solutions didn't work for me in Symfony 5.3. It should be something as basic as

session_start();
session_destroy();

So I did this way:

$this->get('session')->start();
$this->get('session')->invalidate();

This will terminate the PHP Session, which is the way most of sessions work in Symfony.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.