Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Arturexe's avatar

419|PAGE EXPIRED in production, CSRF problem with Laravel 9 and Inertia?

After deployment, when I try to use a delete route, this error is thrown:

419 | PAGE EXPIRED
Failed to load resource: the server responded with a status of 419 ()

Function inside vue component from where the route is triggered:

const destroyEvent = (record) => {
    if (confirm('Delete event?')) {
        Inertia.delete(route('admin.event.destroy', {
            id: record.id,
            title: record.title,
            image_path: record.image_path,
        }), { preserveScroll: true })
    }
}

Web route:

Route::delete('/admin/event/destroy', [EventsController::class, 'destroyEvent'])->name('admin.event.destroy');

The Request does not seem to reach EventsController, which I've tested with dd().

According to this stack question, it might be an CSRF token problem. I've tried everything proposed in there but it didn't help. Though commenting out:

\App\Http\Middleware\VerifyCsrfToken::class

from app\Kernel.php removes the 419 | PAGE EXPIRED screen and instead shows a blank page. Is this an indication of a CSRF problem?

From this laracasts question, I've also tried adding:

public function boot()
    {
        if($this->app->environment('production') || $this->app->environment('staging'))
        {
            \URL::forceScheme('https');
        }
    }

to AppServiceProvider.php with no improvement of the problem.

Any idea how to fix this?

0 likes
19 replies
Arturexe's avatar

I found a workaround by using form.delete instead of Inertia.delete:

const destroyEvent = (record) => {
    if (confirm('Delete Event?')) {
        const form = useForm({
            id: record.id,
            title: record.title,
            image_path: record.image_path
        })
        form.delete(route('admin.event.destroy'), { preserveScroll: true })
    }
}

It would be useful to know how the form helper handles CSRF different from Inertia.

1 like
vincent15000's avatar

@Arturexe Hello, I have exactly the same problem.

Have you found a solution to use Inertia.post instead of form.post ?

vincent15000's avatar

@Arturexe I have used form.post instead of Inertia.post and it works fine. For me, Inertia.post works once a user is connected, but not for logging in a user.

I don't have tried, but I wonder if it's not necessary to add the csrf token manually when using Inertia.post for logging in. Strange idea, but why not.

ashafizullah's avatar

I have the same problem when login or POST. There is unknown status 419, and still not found solution

1 like
aarad's avatar

After using useForm I still have the problem, Nothing changed, is there another solution?

"@inertiajs/vue3": "^1.0.8",

"inertiajs/inertia-laravel": "^0.6.3",

"laravel/framework": "^10.0",

1 like
Reached's avatar

Make sure you dont have the csrf token in the when using Inertia, I used to have this issue :)

Said in another way, make sure you don’t have multiple different csrf instantiations in your application

2 likes
aarad's avatar

@Reached Of course, I didn't use CSRF token anywhere in template, Also sometimes this problem occurs and so far I only had this problem in the Chrome browser, sometimes the temporary problem is solved by clearing the browser cache.

1 like
suddy's avatar

@Reached Hi,

I have same problem just on production, using Laravel 9, I don't use multi different CSRF in my app, and changing browser doesn't helped.

This is my code:

<script setup>
import BreezeButton from '@/Components/Button.vue';
import BreezeCheckbox from '@/Components/Checkbox.vue';
import BreezeGuestLayout from '@/Layouts/Guest.vue';
import BreezeInput from '@/Components/Input.vue';
import BreezeLabel from '@/Components/Label.vue';
import BreezeValidationErrors from '@/Components/ValidationErrors.vue';
import { Head, useForm } from '@inertiajs/inertia-vue3';

defineProps({
    status: String,
});

const form = useForm({
    username: '',
    password: '',
    remember: false
});

const submit = () => {
    form.post(route('admin.login'), {
        onFinish: () => form.reset('password'),
    });
};
</script>

<template>
    <BreezeGuestLayout>
        <Head title="Log in" />

        <BreezeValidationErrors class="mb-4" />

        <div v-if="status" class="mb-4 font-medium text-sm text-green-600">
            {{ status }}
        </div>

        <form @submit.prevent="submit">
            <div>
                <BreezeLabel for="username" value="Username" />
                <BreezeInput id="username" type="text" class="mt-1 block w-full" v-model="form.username" required autofocus autocomplete="username" />
            </div>

            <div class="mt-4">
                <BreezeLabel for="password" value="Password" />
                <BreezeInput id="password" type="password" class="mt-1 block w-full" v-model="form.password" required autocomplete="current-password" />
            </div>

            <div class="block mt-4">
                <label class="flex items-center">
                    <BreezeCheckbox name="remember" v-model:checked="form.remember" />
                    <span class="ml-2 text-sm text-gray-600">Remember me</span>
                </label>
            </div>

            <div class="flex items-center justify-end mt-4">
                <BreezeButton class="ml-4" :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
                    Log in
                </BreezeButton>
            </div>
        </form>
    </BreezeGuestLayout>
</template>

I really need this and I would be appreciate any help.

Thank you

1 like
mmerlijn's avatar

I fixed it by setting http_only to false in de session.php config file. Now, Javascript can read the cookie.

    'http_only' => false,

I also had to change this setting in the Apache config file (old, new)

# Set-Cookie ^(.*)$ ;HttpOnly;Secure;SameSite=None
Set-Cookie ^(.*)$ ;Secure;SameSite=None
1 like
aldiap's avatar

I added usePage().props.csrf_token inside the form, and I found that the issue disappeared. I'm not sure if this is correct or not, but at least it worked for me.

let form = useForm({
    _token: usePage().props.csrf_token,
    // Other form data...
});

For Link

<Link
    :href="$route('logout')"
    :data="{ _token: $page.props.csrf_token }"
>
    {{ __("Logout") }}
</Link>
dualklip's avatar

In my case it was a problem with REDIS, which is my session driver. To check it I changed the value of SESSION_DRIVER to "file". With this change the problem disappeared, but I still wanted to use REDIS. So I guessed that the problem was with the connection to REDIS using the default client (phpredis), so I installed "predis" with this command composer require predis/predis.

Now I don't have the 419|PAGE EXPIRED problem anymore and I can use REDIS as session driver.

1 like
vladkhytrov's avatar

I solved the issue by adding:

window.axios.defaults.withCredentials = true;
window.axios.defaults.withXSRFToken = true;

to the bootstrap.js file. See: laravel . com/docs/11.x/sanctum#cors-and-cookies

I was getting 419 on Inertia requests only.

1 like

Please or to participate in this conversation.