There are several reasons why the token verification may fail:
- Session expiration. The CSRF token is saved in your session, when your session expires the token is lost and the verification done by the
VerifyCsrfToken will fail.
- Session cookie is deleted. A user who blocks cookies or deletes the browser cookies will get a new session leading to the same behavior as if the session has expired.
- An actual cross site request is made and the token really is invalid or missing.
You should be aware that there might be some randomness involved in the session expiration - to be more specific in the session garbage collection (depending on your session config). Unless you set the following config option 'lottery' => [100, 100], in config/session.php.
Session expiration is certainly a problem if a user is not even logged in. Laravel needs to create a session even for a logged out area in order for tokens to work. That means if a user opens your landing page, leaves the site open for a while and returns some time later the session might have expired which will cause a login to fail with a TokenMismatchException exception. The only thing you can do here is to handle that case and ask the user to try again.
If a token mismatch happens in your logged in area and no user exists in your session (=no valid logged in user) you should simply show a warning that the session might have expired and that the user should login again.
Another thing you should do on your site is to check if a user is blocking cookies, that should prevent some of the token mismatches.
@skovmand I know this posting is rather old and maybe you've already solved your problems. But my advice would be to check the logs to see which requests (URLs) caused the token mismatch exception.
Btw. changing php.ini session settings doesn't have any effect since Laravel doesn't use those settings at all. Laravel uses its own session handling which has nothing to do with the PHP session handling.
One general advice regarding sessions in Laravel:
Do not use any other session driver than a cache based one in Laravel. I.e. you should either use redis or memcached.
Some parts of Laravel's implementation of the StartSession middleware are straight up bad and have several flaws, yet the Laravel core developers are not really interested in fixing those:
- garbage collection of session data takes place as part of a request cycle. Whenever the garbage collection takes place the system might need to delete dozens of expired sessions. And this means that the request of the unlucky user who triggered the GC will be delayed for no obvious reason and might even time out. That can be especially problematic if you're using the
file session driver since each session is a file which needs to be deleted.
- even if you set the GC lottery to 100% sessions might not time out as expected. This issue describes pretty much everything regarding this.
- GC works completely different for cache based sessions compared to all other drivers. That's sth. that isn't event documented in Laravel. GC is still called for cache based drivers but it's simply a NOP and has no effect at all. Caches invalidate their entries (and thus their sessions) on their own and automatically delete expired entries. Which of course means that the whole GC lottery thing doesn't have any effect on them but it's still being used by the
StartSession middleware.