Laravel Quick Tip: Handling CsrfToken Expiration gracefully
Quick tip for handling CSRF Token Expiration - common issue is when you use csrf protection is that if
a form sits there for a while (like a login form, but any the same) the csrf token in the form will
expire & throw a strange error.
Handling it is simple, and is a good lesson for dealing with other types of errors in a custom manner.
In Middleware you will see a file VerifyCsrfToken.php and be tempted to handle things there. DON'T!
Instead, look at your app/Exceptions/Handler.php, at the render($request, Exception $e) function.
All of your exceptions go through here, unless you have excluded them in the $dontReport array at the
top of this file. You can see we have the $request and also the Exception that was thrown.
Take a quick look at the parent of VerifyCsrfToken - Illuminate\Foundation\Http\Middleware\VerifyCsrfToken.
You can see from VerifyCsrfToken.php that handle() is the function called to do the token check. In the
parent class, if the token fails, a `TokenMismatchException` is thrown.
So back in the Handler class, let's specifically handle that type of exception:
public function render($request, Exception $e)
{
if ($e instanceof \Illuminate\Session\TokenMismatchException)
{
return redirect()
->back()
->withInput($request->except('password'))
->with([
'message' => 'Validation Token was expired. Please try again',
'message-type' => 'danger']);
}
return parent::render($request, $e);
}
The code is simple - if the exception is a `TokenMismatchException` we will handle it just like
a validation error in a controller. In our forms(s), we need to be sure to use the
$request->old('field_name') (or the old('field_name') helper function) to repopulate. Simply going
"back" will refresh the form with a new token so they can re-submit.
CAREFUL! - I found that using the http://laravelcollective.com/ Form::open() tag seemed to be
incompatible with the token - redirect()->back() was not refresh the token for me. This may just be
something in my code, but when I used a regular html tag it was fine. If this is happening to you,
try that.