symfony/symfony · error · LogicException

Unable to logout with CSRF token validation. Either make sur

Error message

Unable to logout with CSRF token validation. Either make sure that CSRF protection is enabled and "logout" is configured on the "%s" firewall, or bypass CSRF token validation explicitly by passing false to the $validateCsrfToken argument of this method.

What it means

Thrown by `Security::logout($validateCsrfToken = true)` when CSRF validation is requested but either the CSRF token manager service is not registered (CSRF component disabled) or the current firewall has no `logout` config. Logout-with-CSRF needs both to read and validate the configured CSRF parameter/token id.

Source

Thrown at src/Symfony/Bundle/SecurityBundle/Security.php:218

        $request = $this->container->get('request_stack')->getMainRequest();
        if (null === $request) {
            throw new LogicException('Unable to logout without a request context.');
        }

        /** @var TokenStorageInterface $tokenStorage */
        $tokenStorage = $this->container->get('security.token_storage');

        if (!($token = $tokenStorage->getToken()) || !$token->getUser()) {
            throw new LogicException('Unable to logout as there is no logged-in user.');
        }

        if (!$firewallConfig = $this->container->get('security.firewall.map')->getFirewallConfig($request)) {
            throw new LogicException('Unable to logout as the request is not behind a firewall.');
        }

        if ($validateCsrfToken) {
            if (!$this->container->has('security.csrf.token_manager') || !$logoutConfig = $firewallConfig->getLogout()) {
                throw new LogicException(\sprintf('Unable to logout with CSRF token validation. Either make sure that CSRF protection is enabled and "logout" is configured on the "%s" firewall, or bypass CSRF token validation explicitly by passing false to the $validateCsrfToken argument of this method.', $firewallConfig->getName()));
            }
            $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $logoutConfig['csrf_parameter']);
            if (!\is_string($csrfToken) || !$this->container->get('security.csrf.token_manager')->isTokenValid(new CsrfToken($logoutConfig['csrf_token_id'], $csrfToken))) {
                throw new LogoutException('Invalid CSRF token.');
            }
        }

        $logoutEvent = new LogoutEvent($request, $token);
        $this->container->get('security.firewall.event_dispatcher_locator')->get($firewallConfig->getName())->dispatch($logoutEvent);

        $tokenStorage->setToken(null);

        return $logoutEvent->getResponse();
    }

    private function getAuthenticator(?string $authenticatorName, string $firewallName): AuthenticatorInterface
    {
        if (!isset($this->authenticators[$firewallName])) {

View on GitHub (pinned to 698e28026c)

Solutions

  1. Configure a `logout` block on the firewall and ensure the CSRF component is enabled (`symfony/security-csrf` installed and `framework.csrf.enabled: true`).
  2. If CSRF is intentionally off, call `$security->logout(false)` to bypass CSRF validation explicitly.
  3. Install the CSRF package: `composer require symfony/security-csrf`.

Example fix

// before
$security->logout();
// after
$security->logout(false); // bypass CSRF explicitly
Defensive patterns

Strategy: validation

Validate before calling

// Only enforce CSRF when the prerequisites exist:
$fw = $security->getFirewallConfig($request);
$csrfAvailable = $container->has('security.csrf.token_manager');
$logoutConfigured = null !== $fw?->getLogout();
$security->logout($csrfAvailable && $logoutConfigured);

Try / catch

try {
    $security->logout(); // CSRF on
} catch (\Symfony\Component\Security\Core\Exception\LogicException $e) {
    if (str_contains($e->getMessage(), 'CSRF token validation')) {
        $security->logout(false); // bypass explicitly
    } else { throw $e; }
}

Prevention

When it happens

Trigger: Calling `$security->logout()` with the default `$validateCsrfToken = true` on a firewall that has no `logout` block, or in an environment where `security.csrf.token_manager` is unavailable (CSRF disabled). Line 217 checks `has('security.csrf.token_manager')` and `$firewallConfig->getLogout()`.

Common situations: Stateless/API firewalls where logout isn't configured but a controller still calls `logout()`. Disabling CSRF protection globally in tests. Copying a logout call to a new firewall without configuring the `logout` key.

Related errors


AI-assisted analysis of symfony/symfony@698e28026c (2026-08-06). Data as JSON: /api/errors/8eb87d9d3dbe6d53. Report an issue: GitHub.