View as Markdown

Logout Link

A link that logs the current user out through a secure POST form.

100%
Loading...
<twig:LogoutLink class="">
    Logout
</twig:LogoutLink>

Installation

php bin/console ux:install logout-link --kit common

Install the following Composer dependencies:

composer require symfony/security-bundle symfony/security-csrf

Copy the following file(s) into your app:

templates/components/LogoutLink.html.twig
{# @prop firewall string|null The firewall name to log out from; when null, the current firewall is used. #}
{# @block content The link label. #}
{% props firewall = null %}

<twig:PostLink {{ ...attributes.defaults({
    href: logout_path(firewall),
    csrfTokenId: 'logout',
}) }}>
    {{ block(outerBlocks.content)|default('Logout') }}
</twig:PostLink>
templates/components/PostLink.html.twig
{# @prop href string The URL the form submits to. #}
{# @prop csrfTokenId string|null The CSRF token ID used to generate the hidden token field; when null, no token is added. #}
{# @prop method string The HTTP method used to submit the form; when not `POST`, a hidden `_method` field is added for method spoofing. #}
{# @prop confirm string|null A confirmation message shown before submitting; when null, no confirmation is required. #}
{# @block content The button label. #}
{% props href, csrfTokenId = null, method = 'POST', confirm = null %}

<form{{ attributes.nested('form').defaults({
    action: href,
    method: 'post',
    class: 'inline',
    onsubmit: confirm ? 'return confirm(' ~ confirm|json_encode ~ ')' : false,
}) }}>
    {% if method|upper != 'POST' %}
        <input type="hidden" name="_method" value="{{ method|upper }}">
    {% endif %}
    {% if csrfTokenId %}
        <input{{ attributes.nested('csrf').defaults({
            type: 'hidden',
            name: '_csrf_token',
            'data-controller': 'csrf-protection',
            value: csrf_token(csrfTokenId),
        }) }}>
    {% endif %}
    <button{{ attributes.defaults({type: 'submit'}) }}>
        {% block content %}{% endblock %}
    </button>
</form>

Usage

<twig:LogoutLink>
    Logout
</twig:LogoutLink>
Warning

LogoutLink logs the user out through a POST request protected by a CSRF token (token id logout). For it to work, your firewall's logout must require POST and have CSRF protection enabled — otherwise logging out will be rejected.

Restrict the logout route to POST so it can't be triggered by a plain link or prefetch:

#[Route('/logout', name: 'app_logout', methods: ['POST'])]
public function logout(): never
{
    throw new \LogicException('This method is intercepted by the logout key on your firewall.');
}

Point the firewall's logout at that route (app_logout) and enable CSRF protection (this validates the logout token the component sends):

# config/packages/security.yaml
security:
    firewalls:
        main:
            logout:
                path: app_logout
                enable_csrf: true

Examples

Specific Firewall

Set the firewall prop to log out from a specific firewall instead of the current one.

100%
Loading...
<twig:LogoutLink firewall="main" class="">
    Logout from the main firewall
</twig:LogoutLink>

API Reference

Prop Type Default
firewall 
string|null null
Block Description
content The link label.