Sending a CSRF token when making fetch requests with Laravel

July 9th, 2024

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 }
})
Thanks for reading! If you found this article helpful, you might enjoy our practical screencasts too.
Author
Alex Garrett-Smith
Share :

Comments

No comments, yet. Be the first to leave a comment.