1

I have two tabs open in my Laravel application.

I click "logout" in one tab. Then I click "logout" in the second tab. This second logout used to give a 419 error, but I added it to the exclusion list in the VerifyCsrfToken middleware. I don't see why I would need CSRF protection for logging out.

But, now I have a different issue.

After logging out in both tabs, both of them are sitting on the login page. Now if I try to log back in from the first tab, I get a 419 error. From the second tab, the login works correctly.

How can I handle this? I don't want to show an error to the user when they click "login", it's bad user experience. I also don't want to exclude the login route from CSRF protection.

sveti petar
  • 3,637
  • 13
  • 67
  • 144
  • maybe you need jquery ajax every second or something you need check auth middleware if it is true stay on this page else refresh page then you will be automatically go login page for all tab in your browser, except login page you need check all page – Nurbek Boymurodov Dec 08 '20 at 08:49
  • but that example i gave you above it is bad experience, because if you do this then there is no session time for the user it would not work i think that in this case you need rewrite log out function before logging out check auth it is true successfully log out else redirect login page – Nurbek Boymurodov Dec 08 '20 at 08:55
  • The problem is when I try to log back in. Logging out is fine. – sveti petar Dec 08 '20 at 08:59
  • dose my answer satisfy you? – Abilogos Dec 13 '20 at 17:15

2 Answers2

0

Considerations

in this Answer i am naming your browser opened tab as Tab A and Tab B

just consider this following rules:

  • your browser have one session active for a domain at a time (access with session_id cookie).
  • client-side : every opened tab can have a CSRF Token in its forms,header,....
  • server-side : only one csrf token are held in session variable.
  • on every post request, the client and server token should be match, else a 419 error rises.

Necessity of CSRF Protection for logout

no there is no need for preventing CSRF Protection in logout route, since its not a Resource changing route. and it was good that you except=['logout'] from CSRF Protection.

Happening Scenario

1

first you have opened tab A and B they are logged in and shared same session and token

tab A - session 1 - token x tab B - session 1 - token x

2

click on tab A logout. it will cleared session from server . redirect back to login page. in login page, client request to server, made him a new session and token.

tab A - session 2 - token y tab B - session 2 (cookie with session_id are for domain) - token x (client: is presented in tab / removed from server because it was in session 1)

since there is no session 1 in server-side which holds token x so the tab B token mismatched the server y token

3

sending logout on tab B .

if you send logout with csrf enabled. middleware sends you 419 because there is mistmached between token x on client anb b on server .

if its Exempt from csrf , it **clears session ** on server side and redirect client to login page, after redirection server make a new session with a new csrf token for tab B.

i suppose you exempt csrf protection on logout route and continue with second scenario.

tab A - session 3 - token y tab B - session 3 - token z

as you see server has session 3 with token z . so tab A mistmatched

Conclusion

as you saw there was some reasons for this mistmatches:

  • session (cookie) are browser scope but tokens are tab scope
  • user do something on a tab that make other tab to have a session which mistmaches its form token

so as you see The Prevention Solution has get appeared :

if users want to:

  • have multiple tab opend
  • Logout (re-creating session) on one tab
  • continue with other opened tab/forms (a refresh could solve the problem)

Solution

you have to make The Session and token Scope Sync

there are 2 solutions :

  1. make token browser-scope : with using XSRF instead of CSRF which achievable with using SPA client side frameworks. (preferable)

  2. make session page-scope :

    • change logout functionality to not to clear session just clear the response session_id

    • make session tracking with hidden input (which has its downwards itself) (obsolote)

I Recommend to use Single Page Application Frameworks for Client Side

Abilogos
  • 4,777
  • 2
  • 19
  • 39
0

Simple and easy Solution to avoid from "419 page expired":

  1. Go to middleware.
  2. VerifyCsrfToken.php
  3. Create new method handle
    use Closure;

    use Illuminate\Support\Facades\Auth;

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

      return parent::handle($request, $next);
   }
ouflak
  • 2,458
  • 10
  • 44
  • 49