If you're making HTTP requests with JavaScript's Fetch API to web routes in Laravel, you'll need to pass a CSRF token rather than just exclude those routes from CSRF protection.
While not ideal, sending API-style requests to web routes sometimes makes more sense than using actual API routes. Here's how to manually send a CSRF token with fetch.
If you're seeing a 419 Page Expired error when making a request with the JavaScript fetch API, here's how to fix it.
Let's first check how to get the CSRF token in Laravel. Assuming you're using Blade, you can grab it like this:
csrf_token()
This will return the token string, which you can pass along with your request.
Assuming we have a POST route with the endpoint /somewhere
, doing this won't work:
fetch('/somewhere', {
method: 'POST'
})
To send the CSRF token down with this request, send the X-CSRF-TOKEN
header along with your request:
fetch('/somewhere', {
method: 'POST',
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' }
})
Laravel will pick this header up, check the CSRF token and allow the request.
If you're already working with form data, you can send the CSRF token with _form
. Here's what that looks like:
const form = new FormData()
form.append('_token', '{{ csrf_token() }}')
fetch('/somewhere', { method: 'POST', body: form })
So, just append on _form
with the CSRF token and your other form data, and Laravel will recognise and validate this, too.
If you're using Inertia, the process changes slightly since we cannot use the csrf_token
function directly in templates.
Instead, pass this down from your HandleInertiaRequests
middleware first within the share
method:
public function share(Request $request)
{
return array_merge(parent::share($request), [
'csrf_token' => csrf_token()
]);
}
Then, in any of your components:
fetch('/somewhere', {
method: 'POST',
headers: { 'X-CSRF-TOKEN': $page.props.csrf_token }
})
This assumes you're making the request in your templates, where $page
is accessible. However, if you need to access the global csrf_token
prop in your script
section:
import { usePage } from '@inertiajs/vue3'
const page = usePage()
fetch('/somewhere', {
method: 'POST',
headers: { 'X-CSRF-TOKEN': page.props.csrf_token }
})