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:
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:
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:
- Add the CSRF Token to the
<head>
section:
<head>
<meta name="csrf-token" content="{{ csrf_token() }}">
</head>
- Add a call to
$.ajaxSetup
:
<script>
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
</script>
- 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):
<?php
use Illuminate\Support\Facades\Route;
Route::get('/form', function () {
return view('form');
});
Route::post('/formProcessor', function () {
return response('', 200);
});
<!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:
<!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:
- Open the
app/Http/Kernel.php
file in your Laravel project. - Locate the
$middleware
property within theKernel
class. - Find the
VerifyCsrfToken
middleware class, which is typically listed as\App\Http\Middleware\VerifyCsrfToken::class
. - Remove or comment out the line containing the
VerifyCsrfToken
middleware class.
For example, change:
\App\Http\Middleware\VerifyCsrfToken::class,
to:
// \App\Http\Middleware\VerifyCsrfToken::class,
- 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:
- Open the
app/Http/Middleware/VerifyCsrfToken.php
file in your Laravel project. - Within the
VerifyCsrfToken
class, locate theexcept
property. This property specifies the URIs that should be excluded from CSRF token verification. - 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 theexcept
array:
<?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.
- 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 theVerifyCsrfToken
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:
// ...
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!
Good job mate. It was clear explanation for the new comers.
Thanks for leaving a comment, it is very encouraging to know the post was useful to you. Happy coding!