Laravel + Vue.js (axios) - CSRF token mismatch
Asked Answered
E

6

10

I have problem with csrf token in Laravel. Sometimes request POST (via axios) returns 419 code "CSRF token mismatch" but request header contain CSRF and XSRF tokens. Interestingly, it's not happend in incognito mode.

enter image description here

App.blade:

<meta name="csrf-token" content="{{ csrf_token() }}">

bootstrap.js:

window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';


let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

Kernel.php:

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            \App\Http\Middleware\Localization::class,
        ],

I tried to clear cache and config with no results. Any ideas how to fix it?

Enlil answered 22/12, 2019 at 22:47 Comment(4)
You say it sometimes works sometimes doesn't? Does it fail when you're submitting forms?Buckram
It's happens randomly (for example when user try to log out or send a message via form).Enlil
I recommend this article.Whose
I answered a related question here: https://mcmap.net/q/1163670/-how-to-use-laravel-sanctum-with-two-different-frontend-and-backend-domains on csrf token mismatch.Biconcave
G
1

Sometimes?! It sounds like a expired token.

When you're working in incognito tabs, you have a fresh token.

Try location.reload() when you're getting 419 error code and everything goes well.

Greet answered 23/12, 2019 at 0:24 Comment(0)
N
10

I encountered this issue. The cause was axios headers not being set. Setting them on the axis object within the component also did not resolve the issue. Setting the headers after the object is defined resolved the issue for me.

In your blade view add the following:

<script>window.Laravel = {csrfToken: '{{ csrf_token() }}'}</script>

In your bootstrap.js file, after declaring window.axios = require('axios'); add the following:

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = window.Laravel.csrfToken;
Nereus answered 9/12, 2020 at 14:28 Comment(4)
Man, thanks you very much! I lost two days before find your answer! It's WORKS!!!! YEAH!Festus
Give this man a medal! Thank you very much man.Giuseppinagiustina
Hi there, i encouter the same problem its very sporadic and most of the time the XSRF token is set. However sometimes its not, Kevin, do you know if this approach will conflict with the automatic behavior that axios has of setting XSRF token in lararvel? Thanks.Whap
it's more recomended to use a meta tag in the header : <meta name="csrf-token" content="{{ csrf_token() }}"> and then document.head.querySelector('meta[name="csrf-token"]').content to retrieve the tokenErdda
E
3

I've the problem when fecthing data from laravel database (webA) in another website(webB). After some research, I find Laravel already has one solution for this senario: https://laravel.com/docs/5.7/csrf to exclude the route you are visiting from another web. In VerifyCsrfToken.php, exclude the route or page.

<?php
    
    namespace App\Http\Middleware;
    
    use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
    
    class VerifyCsrfToken extends Middleware
    {
        /**
         * The URIs that should be excluded from CSRF verification.
         *
         * @var array
         */
        protected $except = [
            'stripe/*',
            'http://example.com/foo/bar',
            'http://example.com/foo/*',
        ];
    }
Evanish answered 31/1, 2022 at 19:58 Comment(1)
This is not a correct approach and it creates security vulnerabilities.Shote
G
1

Sometimes?! It sounds like a expired token.

When you're working in incognito tabs, you have a fresh token.

Try location.reload() when you're getting 419 error code and everything goes well.

Greet answered 23/12, 2019 at 0:24 Comment(0)
N
1

I think the token is expired in your case. You can intercept http status 419 (non standard status defined by Laravel) and reload the page to generate a new CSRF token :

window.axios.interceptors.response.use(
    response => response.data,
    error => {
        if (error.response && 419 === error.response.status) {
            window.location.reload()
        }

        return Promise.reject(error)
    }
)
Ninny answered 16/9, 2021 at 13:15 Comment(1)
this is my preferred approach. though i have made slight changes to my Axios.js module since the returned response from laravel isn't an actual error. the best thing about this solution is that you can centralize the token_mismatch issue in a single file like a middleware instead of verifying within every component.Longer
P
1

Please note that difference between http and https from client to server creates this error as well; Meaning that even if all your configs are ok, if https is not enforced and client uses http, then this error is produced.

Premiership answered 25/1, 2023 at 13:59 Comment(1)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewYarmouth
B
-1

On your front-end application startup, always send a request to /sanctum/csrf-cookie, with axios withCredentials:true set up.

Remember to set supports_credentials => true in laravel cors.php config file.

And set SANCTUM_STATEFUL_DOMAINS in .env file correctly,

SANCTUM_STATEFUL_DOMAINS=127.0.0.1:8000,127.0.0.1:3000,localhost:3000

It's better to have exact one root domain in front-end and backend.

Byrnie answered 28/9, 2023 at 6:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.