0

I'm using larvel 8 and want to change message of "CSRF token mismatch" when using ajax post. I created a closure and passed it to the renderable method on the App\Exceptions\Handler class, but the previews message appears. This is my code:

use Illuminate\Session\TokenMismatchException;
class Handler extends ExceptionHandler
{
    protected $dontReport = [
        //
    ];

    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];

    public function register()
    {
        $this->renderable(function (TokenMismatchException $e, $request) {
            return $request->expectsJson()
                ? response()->json(['message' => 'A new message...'], 419)
                : redirect()->guest(route('login'));
        });    
    }

3 Answers3

3

To modify error message on TokenMismatchException both for web-pages and ajax-requests

It would be better to overload prepareException() method in application exception handler:

    protected function prepareException(Exception $e)
    {
        if ($e instanceof TokenMismatchException) {
            $e = new HttpException(419, __('exception.csrf_token_mismatch'), $e);
        }

        return parent::prepareException($e);
    }

So you can create translation file and modify message by language files. For example create resources/lang/en/exception.php with content below:

<?php

return [
    'csrf_token_mismatch' => 'CSRF token mismatch. Please, refresh page (CTRL+R) and try again.',
];
likemusic
  • 198
  • 1
  • 8
1

thanks to everyone who contributed, I found the solution.

Due to laravel change the TokenMismatchException to HttpException in the function prepareException in the Illuminate\Foundation\Exceptions\Handler class(parent of Handler class), we cannot render the TokenMismatchException.

protected function prepareException(Throwable $e)
    {
        if ($e instanceof ModelNotFoundException) {
            $e = new NotFoundHttpException($e->getMessage(), $e);
        } elseif ($e instanceof AuthorizationException) {
            $e = new AccessDeniedHttpException($e->getMessage(), $e);
        } elseif ($e instanceof TokenMismatchException) {
            $e = new HttpException(419, $e->getMessage(), $e);
        } elseif ($e instanceof SuspiciousOperationException) {
            $e = new NotFoundHttpException('Bad hostname provided.', $e);
        } elseif ($e instanceof RecordsNotFoundException) {
            $e = new NotFoundHttpException('Not found.', $e);
        }

        return $e;
    }

I modify my renderable method as below and now I can catch the TokenMismatchException:

$this->renderable(function (HttpException $e, $request) {
    if ($e->getPrevious() instanceof TokenMismatchException) {
        return $request->expectsJson()
            ? response()->json(['message' =>'Your new message ...', 419)
            : redirect()->guest(route('login'));
    }
});
0

If you want to change the error message or the page that is shown when CSRF token mismatch happen

Run this command: php artisan vendor:publish --tag=laravel-errors

It will publish your default (vendor) exceptions page to resources/views/errors/

From there, edit resources/views/errors/419.blade.php with html that you would like to show when CSRF verification error happen.

References: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes

419 Page Expired (Laravel Framework)
    Used by the Laravel Framework when a CSRF Token is missing or expired.

If you want to allow ajax requests to bypass CSRF token verification

Reference: https://laravel.com/docs/8.x/csrf#csrf-excluding-uris

Edit your VerifyCsrfToken middleware (location: app/Http/Middleware/VerifyCsrfToken.php), add:

class VerifyCsrfToken extends Middleware
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        'stripe/*',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ];
}
Kristian
  • 2,456
  • 8
  • 23
  • 23
  • I used an ajax post request. Before the session expired, everything worked fine, but this request gets the message "CSRF token mismatch" once it expired. I want to translate this message to another language. Due to ajax request, changing the 419 error blade file is not beneficial. – Hamid Reza Valizadeh Feb 25 '21 at 10:31
  • @HamidRezaValizadeh see https://laravel.com/docs/8.x/localization for translation – Kristian Feb 25 '21 at 11:09