419 page expired error in Laravel

419 page expired Laravel error occurs when the valid CSRF token missing in the post request or when the page takes too long to send the post request which leads to expiring the CSRF token.

CSRF or Cross-Site Request Forgery is a type of malicious exploit whereby unauthorized commands are performed on behalf of an authenticated user. Laravel Framework has an internal mechanism for CSRF protection that is enabled by default for all POST, PUT, PATCH, and DELETE requests within web routes. A CSRF Token is a secret value generated by the server and checked in the subsequent HTTP POST, PUT, PATCH, and DELETE requests made by the client.

To solve 419 page expired error in Laravel, we have to use the CSRF token in our post requests. Here is an example showing how to use the CSRF token in a form to make a POST request.

<form action="/save" method="POST">
	@csrf
	<input type="text" name="name"/>
	<button type="submit">Save</button>
</form>

The blade template has a built-in directive @csrf that will generate a hidden HTML input containing the token. The @csrf directive should be added inside the <form> tag. @csrf is equivalent to:

<input type="hidden" name="_token" value="{{ csrf_token() }}" />

For an Ajax request, the solution is a little different. We are adding a CSRF token in the header of the Ajax requests. For this first, we add csrf_token in the meta tag as given below example.

<head>
    <meta name="csrf-token" content="{{ csrf_token() }}" />
</head>
<script>
	function sendPostRequest(){
		var data = {
			name: $("#name").val()
		};
		var headers = {
    		'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
		}

		$.ajax({
    		url: "/save",
    		type: "post",
    		headers: headers,
    		data: data,
    		success:function(res){
    			
    		}
		});
	}
</script>

Then we took the token from the meta tag and added it to the header of the Ajax request.

Disabling CSRF Protection for some routes

The App\Http\Middleware\VerifyCsrfToken middleware was included in the web middleware group by default. So this middleware will automatically check all POST requests in web routes and verify that the token in the request matches the token stored in the session. When these two tokens match, we know that the request was initiated by an authenticated user.

In some cases, we may want to exclude a set of routes from CSRF protection. For example, if we are working with Stripe for payments and we may be utilizing their webhook system. In this scenario, we will need to exclude the Stripe routes from CSRF protection.

We can disable CSRF protection for route groups or specific routes in Laravel. For this open App\Http\Middleware\VerifyCsrfToken middleware. In the VerifyCsrfToken.php file, we can add route groups or specific routes in an array to be excluded from CSRF protection in the $except array variable. 

// /app/Http/Middleware/VerifyCsrfToken.php
class VerifyCsrfToken extends Middleware
{
    protected $except = [
        'payments/*',  // exclude all URLs with prefix payment/
        'product/add' // exclude exact URL
    ];
}

Conclusion

CSRF protection is enabled by default for all POST requests within web routes in Laravel. We have to pass the CSRF Token generated by the server along with all post requests and it will be verified by VerifyCsrfToken middleware. The blade directive @csrf will generate a hidden HTML input containing the token inside the form.