Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

sstier's avatar
Level 33

Catching TokenMismatchExceptions in handler

Hi, I have a very small project that I need some help on. I have laptop users who leave the page open and close the laptop. This stops my javascript that I use to refresh the token periodically., which leads to TokenMismatchExceptions on form submit. I've tried to catch that in the handler.php file, but it doesn't seem to work. I'm still getting the TokenMismatchExceptions error page rather than a redirect. I've set my environment variables as such for testing in the production environment.

Any help will be greatly appreciated.

Thanks.

APP_ENV=production
APP_DEBUG=true
<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

use Illuminate\Session\TokenMismatchException;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that should not be reported.
     *
     * @var array
     */
    protected $dontReport = [
        \Illuminate\Auth\AuthenticationException::class,
        \Illuminate\Auth\Access\AuthorizationException::class,
        \Symfony\Component\HttpKernel\Exception\HttpException::class,
        \Illuminate\Database\Eloquent\ModelNotFoundException::class,
        \Illuminate\Session\TokenMismatchException::class,
        \Illuminate\Validation\ValidationException::class,
    ];

    /**
     * Report or log an exception.
     *
     * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
     *
     * @param  \Exception  $exception
     * @return void
     */
    public function report(Exception $exception)
    {
        parent::report($exception);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $exception
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $exception)
    {
        if ($exception instanceof TokenMismatchException)
        {
        return redirect()->back()->with("error", "Page had expired.  Please try again.");
        }
        
        return parent::render($request, $exception);
    }

    /**
     * Convert an authentication exception into an unauthenticated response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Illuminate\Auth\AuthenticationException  $exception
     * @return \Illuminate\Http\Response
     */
    protected function unauthenticated($request, AuthenticationException $exception)
    {
        if ($request->expectsJson()) {
            return response()->json(['error' => 'Unauthenticated.'], 401);
        }

        return redirect()->guest(route('login'));
    }
}


0 likes
8 replies
bashy's avatar

That's how I've seen it done. Works fine.

public function render($request, Exception $exception)
{
    // Redirect back with input if token is wrong/expired
    if ($exception instanceof TokenMismatchException) {
        return back()
            ->withInput($request->merge(['_token' => csrf_token()]))
            ->with('error', 'Security token wrong or expired.');
    }

    return parent::render($request, $exception);
}
1 like
sstier's avatar
Level 33

I'm just very confused as to why it's not :( I've changed the environment variable to

APP_ENV=production
APP_DEBUG=false

In case being in debug was causing issues. But same result.

I'll have to see why the if statement is not working.

If i deliberately provide an invalid token in the form by appending "a", and return the $exception in the render method, I get this exception in the browser with the stack trace:

Symfony\Component\Debug\Exception\FatalThrowableError: Type error: Argument 1 passed to Illuminate\Cookie\Middleware\EncryptCookies::encrypt() must be an instance of Symfony\Component\HttpFoundation\Response, instance of Symfony\Component\Debug\Exception\FatalThrowableError given, called in /home/vagrant/Code/tb/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php on line 59 in /home/vagrant/Code/tb/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php:123

But once it's rendered, I get the TokenMismatchException. I there something I'm not getting? :( Being an amateur is hard.

Thyrosis's avatar
Thyrosis
Best Answer
Level 17

To debug, as soon as you hit the render-method, dd($exception).

You're probably looking to match Illuminate\Session\TokenMismatchException, not just TokenMismatchException. Unless you import Illuminate\Session\TokenMismatchException of course.

Thyrosis's avatar

@bashy I don't think it will. The instanceof will just check if the given object is an instance of a given class by checking the class and of the model against the name given.

It will not check if the given class and actually exists. For the instanceof check, its just a name, nothing more. That's why you need to import the class or use it's full path for this to work.

sstier's avatar
Level 33

I'm importing it on top using :

use Illuminate\Session\TokenMismatchException;

And dd($exception) gives me the following.

TokenMismatchException {#311 ▼
  #message: ""
  #code: 0
  #file: "/home/vagrant/Code/tb/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php"
  #line: 68
  trace: {▶}
}

So everything should work right? I'm not sure why it's not :(

sstier's avatar
Level 33

Okay I'm seriously not sure what happened. But I just deleted the handle.php file, copied a fresh one and added the same code. And now it works.

I don't know what's happening.

Thanks for helping track it down guys. The dd($exception) was insanely helpful in figuring out the right exception was being thrown!

bashy's avatar

@Thyrosis Interesting, never really thought about it. Looks like that wasn't the issue though anyway :P

Please or to participate in this conversation.