Laravel 5.8 showing "419 Page Expired" after clicking logout from an already cleared session
Asked Answered
D

7

23

I run the php artisan make:auth command and I will explain step by step what I do after that to understand the scenario,

  • Login to a new session (example.com/home)
  • opened a new tab and pasted the URL, ie example.com/home.
  • Now 2 tabs are open with the same session.
  • I clicked logout from one of the tabs and it works perfectly fine
  • Then when I tried to logout from the other tab, it gave me an error saying "419 Page Expired" and it is going nowhere even after reloading.

The thing is, these kinds of scenarios may arise, and I don't want to see this error message, just logout after clicking logout, even if the session is expired.

Note: This issue is not because of not adding @csrf

Donnetta answered 18/7, 2019 at 12:41 Comment(0)
K
50

Well that's an obvious message you can maybe try to make a better layout for that page, but still it is good to show it so the user knows what happened. If you want to handle it differently you can try to redirect to the login page.

So in your app\Exceptions\Handler.php file within the render method add this:

if ($exception instanceof \Illuminate\Session\TokenMismatchException) {
    return redirect()->route('login');
}
Kokand answered 18/7, 2019 at 12:57 Comment(4)
Hi, this works, Thansk! But when I tries multiauth, the 419 page not found scenario in admin session redirecting my admin login url to this (redirect()->route('login')) (ie to the user login)Donnetta
Then redirect to a different page, you probably have one in common for both admins and users, that one will redirect to which login page needs to redirect you to.Kokand
Yes, I got my solution, will check with the current url and redirect accordingly.. Thanks for the help brother..Donnetta
To be more precise, create a public function logout() function in your app\Exceptions\Handler.php file and put the above code inside.Urbanist
L
11

A solution to the problem is relatively simple and requires a small addition to the VerifyCsrfToken middleware;

use Closure;


    public function handle($request, Closure $next)
    {
        if(!Auth::check() && $request->route()->named('logout')) {
        
            $this->except[] = route('logout');
            
        }
        
        return parent::handle($request, $next);
    }

Usually, this file contains just an $except array of routes that should be ignored from csrf.

In this code, we override the handle method and perform two checks.

  • is the user a guest (ie, not using an authenticated session), and,
  • is the route the logout route

If both are true then we add 'logout' to the except array. We then pass control to the core VerifyCsrfMiddleware which recognises the presence of the logout route in the array, and bypasses the check. The form data is correctly posted and we are redirected using the LogoutResponse.

The user sees no error page.

By checking in this way, we ensure that CSRF Token still protects genuine logout requests.

Lugar answered 15/9, 2020 at 23:1 Comment(3)
Below use Closer; add use Auth; For newbies, in a Laravel 7 project it's in /app/Http/Middleware/VerifyCsrfToken.php. Here's the complete VerifyCsrfToken.php file below. <?php namespace App\Http\Middleware; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware; use Closure; use Auth; class VerifyCsrfToken extends Middleware { /** * The URIs that should be excluded from CSRF verification. * * @var array */ protected $except = [ // ]; }Tiertza
SO has some wiered rules "Comments can only be edited for 5 minutes." So the above has some missing details. Oh well.Tiertza
Yes. Good for Laravel 7 and 8.Lugar
R
3

It's never too late)

Add app/Http/Middleware/VerifyCsrfToken.php

    use Closure;

    public function handle($request, Closure $next)
    {
        if($request->route()->named('logout')) {
            if (auth()->check()) {
                auth()->logout();
            }

            return redirect('/');
        }
    
        return parent::handle($request, $next);
    }

I think these are the best solutions.

Rattlebrain answered 8/9, 2021 at 0:45 Comment(1)
Logout logic shouldn't be in the VerifyCsrfToken middleware.Earle
R
2

IMHO you can try to modify your app/Http/Middleware/VerifyCsrfToken.php file. Edit the the $except property with something like this:

class VerifyCsrfToken extends Middleware
{       
    protected $except = [
        'http://example.com/logout',
    ];
Rabideau answered 18/7, 2019 at 13:8 Comment(4)
Hi, Thanks for the answer.Donnetta
This completely disables csrf protection for this route.Corneliuscornell
very bad and insecure solution.Tieck
This is not a solution, only a security flaw.Vigen
T
2

In a Laravel 6 project, I ended up modifying the VerifyCsrfTokenMiddleware as follows

As you will see, I simply added the logout named route to list of exclusion.

I overridden the __construct function because we cannot use route() function when initializing a new variable

<?php

namespace App\Http\Middleware;

use Illuminate\Contracts\Encryption\Encrypter;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    /**
     * Indicates whether the XSRF-TOKEN cookie should be set on the response.
     *
     * @var bool
     */
    protected $addHttpCookie = true;

    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [

    ];

    /**
     * Create a new middleware instance.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @param  \Illuminate\Contracts\Encryption\Encrypter  $encrypter
     * @return void
     */
    public function __construct(Application $app, Encrypter $encrypter)
    {
        parent::__construct($app, $encrypter);
        $this->except = [
            route('logout')
        ];
    }
}
Technics answered 27/3, 2020 at 11:49 Comment(4)
Blanket removal of the logout csrf token is a security weakness and not recommended. Forcibly logging users out with a csrf attack may cause them to disclose login credentials whilst they are being monitored.Lugar
Could you point me to documentation of this problem? and ... what do you suggest? I cannot have user complaining because they cannot logout due to csrf token expiration.Technics
one example security.stackexchange.com/questions/62769/…Lugar
I have suggested a solution as an answer to this post. Add the logout route to the except rules only if the user's session has already expired.Lugar
B
-2
<a href="{{ route('logout') }}" class="dropdown-item notify-item"="event.preventDefault(); document.getElementById('logout-form').submit();">
    <i class="fa fa-power-off"></i>  <span>{{ __('Logout') }} </span>
    </a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
  @csrf
</form>

You have missed the @csrf in you logout form, so only you getting Error 419

Barozzi answered 18/7, 2019 at 13:17 Comment(1)
Sorry mate, that is not the problem, I already mentioned this in my question.Donnetta
D
-3

You need to add the CSRF Token to your form:

<form action="{{ route('logout') }}" method="POST">
    @csrf
    <button type="submit" class="btn nav-link">Logout</button>
</form>

Laravel 8.x Docs

Dallapiccola answered 12/3, 2021 at 15:12 Comment(1)
Please read the note in the question Note: This issue is not because of not adding @csrfDonnetta

© 2022 - 2024 — McMap. All rights reserved.