3

How can i force logout user logged from controle on the new Symfony 6 ? (Version 6.0.1)

I tried $tokenStorage->setToken($token); but setToken() need 2 args:

(public function setToken(string $tokenId, string $token);)

I tried $request->getSession()->invalidate(); but my user is always logged...

I want to logout the user and redirect to another route (à don't want redirect to logout route)

Thank you


I can't use /logout because i'm in a controller, and sometime I have to make sure no user is logged, because i do treatment when I'm comming to this route.

I need this:

When i go to /validate route:

  • if user : logged => logout
  • change somethings to my user, other user and flush some logs to bdd
  • redirect to login page to force login back the user

My service:

<?php

namespace App\Service;

use Symfony\Component\Security\Http\Event\LogoutEvent;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

class SecurityService
{

    public function forceLogout(
        Request $request,
        EventDispatcherInterface $eventDispatcher,
        TokenStorageInterface $tokenStorage) : void
    {
        $logoutEvent = new LogoutEvent($request, $tokenStorage->getToken());
        $eventDispatcher->dispatch($logoutEvent);
        $tokenStorage->setToken(null);
    }
}

This don't work, my $eventDispatcher->dispacth($logoutEvent) work only before i refresh my page, after i'm logged again !

3
  • Normally you can do $tokenStorage->setToken(null); not sure if this has changed for Symfony 6. How about $id = $tokenStorage->getToken()->getId(); then you can ...->setToken($id, null); Commented Apr 27, 2022 at 21:30
  • The TokenStorageInterface in Symfony 6 doesn't seem to require 2 arguments. $tokenStorage->setToken(null) works fine on my end. Commented Apr 27, 2022 at 22:21
  • I don't have a 6.0 example handy but basically you need to dispatch a LogoutEvent and then set the token to null. Take a look at the source code for Symfony\Component\Security\Http\Firewall\LogoutListener::authenticate and basically copy the relevant code. I know there was talk at one time of encapsulating this functionality into an official Logout service but I don't think that even happened. It is important you send the event even if things seem to work without it. You can easily run into hard to debug issues without it. Commented Apr 28, 2022 at 13:19

3 Answers 3

7

I found soluce :

public function forceLogout() : void
{
    $logoutEvent = new LogoutEvent($this->requestStack->getCurrentRequest(), $this->tokenStorage->getToken());
    $this->eventDispatcher->dispatch($logoutEvent);
    $this->tokenStorage->setToken(null);
    $response = new Response();
    $response->headers->clearCookie('REMEMBERME');
    $response->send();
}
Sign up to request clarification or add additional context in comments.

1 Comment

This aided me in figuring out what to do. But my company is only using symfony 4.4 so logoutEvent class does not exist. What I did is using the token interface set to null and also invalidate the session.
4

Since 6.2 we have a Symfony/Bundle/SecurityBundle/Security helper class. This has methods to login/logout programmatically.

Examples from the docs:

// src/Controller/SecurityController.php
namespace App\Controller\SecurityController;

use App\Security\Authenticator\ExampleAuthenticator;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;

class SecurityController
{
    public function someAction(Security $security): Response
    {
        // get the user to be authenticated
        $user = ...;

        // log the user in on the current firewall
        $security->login($user);

        // if the firewall has more than one authenticator, you must pass it explicitly
        // by using the name of built-in authenticators...
        $security->login($user, 'form_login');
        // ...or the service id of custom authenticators
        $security->login($user, ExampleAuthenticator::class);

        // you can also log in on a different firewall...
        $security->login($user, 'form_login', 'other_firewall');

        // ...and add badges
        $security->login($user, 'form_login', 'other_firewall', [(new RememberMeBadge())->enable()]);

        // use the redirection logic applied to regular login
        $redirectResponse = $security->login($user);
        return $redirectResponse;

        // or use a custom redirection logic (e.g. redirect users to their account page)
        // return new RedirectResponse('...');
    }
}
// src/Controller/SecurityController.php
namespace App\Controller\SecurityController;

use Symfony\Bundle\SecurityBundle\Security;

class SecurityController
{
    public function someAction(Security $security): Response
    {
        // logout the user in on the current firewall
        $response = $security->logout();

        // you can also disable the csrf logout
        $response = $security->logout(false);

        // ... return $response (if set) or e.g. redirect to the homepage
    }
}

Comments

3

just redirect to the logout route:

return $this->redirect($this->generateUrl('YourLogoutRouteName'));

3 Comments

I don't want redirect to logout root, because à need to logout the user and redirect to another root
then maybe an event listener on the logout event. symfony.com/blog/… but not sure if you can redirect from there.
You can, the event exposes the setResponse method.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.