How to Fix 419 Page Expired/CSRF token mismatch in Laravel?

Using CSRF tokens adds an extra layer of security by validating that the request originates from the same application and not from a malicious source.

Laravel provides built-in protection against CSRF attacks by generating and validating CSRF tokens. However, its incorrect use can lead to the error: 419 Page Expired as Shown in the screenshot below:

Default Laravel Error Page Showing Error 419 Page Expired

To fix the “419 Page Expired” error, you need to ensure the CSRF token is included in the submitted form by adding @csrf after between the opening and closing <form> tags. By doing so, a hidden input field will be automatically added to the form, containing the CSRF token.

Here’s an example of how the updated form would look using @csrf in blade code:

<form method="POST" action="/your-route">
    @csrf
    <!-- Rest of your form elements -->
</form>

Alternatively, you could also use csrf_field() in your form which looks like this:

<form method="POST" action="/your-route">
    {{ csrf_field() }}
    <!-- Rest of your form elements -->
</form>

Note that a 419 Page Expired error can also occur when the token is present. Usually this means the user was inactive for a certain time and the token is indeed expired. This is remedied simply by refreshing the page and sending the form anew.

In the code examples above, we learned how to apply the token to a regular form. Read on to learn how the CRSF token is added to Ajax POST requests using jQuery or Axios. We will also learn methods to disable CSRF token validation for a specific route or the entire application. Finally, we will answer some frequently asked questions about why a GET request doesn’t require CSRF verification and why APIs don’t require them at all.

Let’s get started!

How to Fix “419 (unknown status)” With Ajax POST (jQuery)

When posting a form using AJAX from jQuery you might receive an error response as shown in your browser console and network tab:

Error 419 (unknown status) on jQuery AJAX POST as Shown in Google Chrome Console

Using Laravel/jQuery you can fix the error “419 (unknown status)” by adding a csrf_token() call in your <head> section and calling to $.ajaxSetup to configure jQuery to add the token to the headers of all subsequent POST requests.

Follow these steps to apply this fix to your code:

  1. Add the CSRF Token to the <head> section:
<head>
   <meta name="csrf-token" content="{{ csrf_token() }}">
</head>
  1. Add a call to $.ajaxSetup:
<script>
    $.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
    });
</script>
  1. Add jQuery code to send POST request:
<script>
    // Send a shorthand jQuery POST:
    $.post('/formProcessor');

    // Or send a regular jQuery POST:
    $.ajax({
        type: "POST",
        url: "/formProcessor"
    });
</script>

The full example (route and view):

routes/web.php
<?php

use Illuminate\Support\Facades\Route;

Route::get('/form', function () {
    return view('form');
});

Route::post('/formProcessor', function () {
    return response('', 200);
});
resources/views/form-jquery-ajax.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Laracoding.com - jQuery Ajax POST Example</title>
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
</head>
<body>
    <button class="sendButton">Click me</button>
    <script>
        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        });
        $('.sendButton').click(function(){
            $.post('/formProcessor');
        });
    </script>
</body>
</html>

Using Axios to Send Ajax POST (No Need to Set CSRF Token)

Axios is an HTTP Client for JavaScript. It makes sending AJAX POST requests a lot easier. It does so by eliminating the need to include jQuery, to set a token, or to call a setup function. I personally would recommend using Axios in any project that sends Ajax requests from JavaScript.

By default Laravel ships with Axios and Vite. In order to use Axios we merely need to run the following commands:

npm install
npm run build

These commands installed Axios and generated the correct .js file into your /public folder

You can now include app.js and use Axios in your code to send an example POST request as shown in this example:

resources/views/form-axios-ajax.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Laracoding.com - jQuery Ajax POST Example</title>
    @vite(['resources/js/app.js'])
</head>
<body>
<button class="sendButton">Click me</button>
<script>
    document.querySelector('.sendButton').addEventListener('click', function (event) {
        axios.post('/formProcessor', {
            // Request payload
            data: 'your-data'
        }).then(response => {
            // Handle response
            alert('succesful!');
        }).catch(error => {
            // Handle error
            console.error(error);
        });
    });
</script>
</body>
</html>

How to disable CSRF Token Verification in Laravel?

To disable CSRF token verification for all routes in Laravel you can remove the CSRF middleware by following these steps:

  1. Open the app/Http/Kernel.php file in your Laravel project.
  2. Locate the $middleware property within the Kernel class.
  3. Find the VerifyCsrfToken middleware class, which is typically listed as \App\Http\Middleware\VerifyCsrfToken::class.
  4. Remove or comment out the line containing the VerifyCsrfToken middleware class.
    For example, change:
app/Http/Kernel.php
\App\Http\Middleware\VerifyCsrfToken::class,

to:

app/Http/Kernel.php
// \App\Http\Middleware\VerifyCsrfToken::class,
  1. Save the changes to the Kernel.php file.

By removing the VerifyCsrfToken middleware, CSRF token verification will be disabled for all routes in your Laravel application. However, keep in mind that this approach removes an important security measure, so use it with caution and only in specific cases where CSRF protection is not required.

How to disable CSRF Token Only for A Specific Route

To disable CSRF token verification for a specific route in Laravel, you can exclude the route from CSRF protection by modifying the CSRF middleware. Here’s how you can do it:

  1. Open the app/Http/Middleware/VerifyCsrfToken.php file in your Laravel project.
  2. Within the VerifyCsrfToken class, locate the except property. This property specifies the URIs that should be excluded from CSRF token verification.
  3. Add the URI of the route you want to exclude from CSRF protection to the except array.For example, if you want to exclude the route /example from CSRF verification, add the following line to the except array:
app/Http/Middleware/VerifyCsrfToken.php
<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    protected $except = [
        //
    ];
}

If you have multiple routes to exclude, you can add them comma-separated within the array.

  1. Save the changes to the VerifyCsrfToken.php file.

There are legitimate use cases for disabling VerifyCsrfToken for specific routes. One example is to enable our application to receive callbacks from a third-party system, such as a payment provider. This is typically used to update the order status to paid.

By adding the specific route to the except array in the VerifyCsrfToken middleware, Laravel will bypass CSRF token verification for that route. It’s important to note that while this approach can be useful in certain scenarios, disabling CSRF protection should be done cautiously and only when necessary to ensure the security of your application.

Why Laravel API Routes Don’t Use CSRF Verification

It’s worth noting that, in Laravel, the CSRF token verification middleware is intentionally not automatically added to API routes.

Laravel API routes do not use CSRF (Cross-Site Request Forgery) verification by default due to their stateless nature. APIs typically operate in a stateless manner, meaning they do not store session data or maintain client state between requests.

Instead, APIs utilize token-based authentication mechanisms like JWT (JSON Web Tokens) or OAuth for request authentication and authorization. This token-based authentication provides a secure mechanism without the need for CSRF tokens. For traditional web forms, however, CSRF protection remains crucial.

Why Laravel GET Requests Don’t Apply CSRF Token Verification

The CSRF token is required in any POST, PUT, PATCH, or DELETE requests that are sent from a website. But why is it not required when we send a GET request?

GET requests, are typically used for retrieving data and are considered safe, as they should not modify any server-side data. Since CSRF attacks rely on unauthorized modifications, applying CSRF tokens to GET requests is unnecessary.

For completeness’ sake, it is worth mentioning that OPTIONS and HEAD requests are also considered read-only requests which, like GET requests, do not require a check of the CSRF token. As the official VerifyCsrfToken Middleware code shows:

Illuminate\Foundation\Http\Middleware\VerifyCsrfToken.php
// ...

protected function isReading($request)
{
    return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']);
}

// ...

Conclusion

This blog post addressed how to remedy “419 Page Expired” and “CSRF token mismatch” errors in Laravel when using either regular forms or Ajax-based POST requests sent with either jQuery or Axios.

Furthermore, the blog post showed how one might disable CSRF token verification for a specific route and how it can be disabled entirely. Finally, we also clarified why API routes do not use CSRF token verification by default and why GET requests in Laravel don’t verify the CSRF token.

I hope this post will be helpful to you. Happy Coding!

Johan van den Broek

Johan is the creator of laracoding.com. As a child, he began tinkering with various programming languages, many of which have been long forgotten today. Currently, he works exclusively with PHP and Laravel, and his passion for programming remains to this day.

Leave a Reply

Your email address will not be published. Required fields are marked *

Recent Posts