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

fylzero's avatar
Level 67

Laravel Shift 10.x to 11x CSRF Token Mismatch

I just ran Laravel Shift from 10.x to 11.x and seem to be getting CSRF errors across the board. I've been poking around at this for a bit but can't seem to figure this out so far. Has anyone run into this or have anything to suggest trying to solve this problem? Thanks!

0 likes
20 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

It sounds like you're experiencing a common issue that can occur after upgrading Laravel versions, which is related to changes in how CSRF protection is handled or session configuration issues. Here are some steps you can take to troubleshoot and resolve CSRF token mismatch errors after upgrading to Laravel 11.x:

  1. Clear Your Application Cache Laravel caches a lot of configuration and route information for performance. After an upgrade, it's a good idea to clear these caches to ensure that old, potentially incompatible configuration isn't causing issues.

    Run the following commands in your terminal:

    php artisan cache:clear
    php artisan config:clear
    php artisan route:clear
    php artisan view:clear
    
  2. Regenerate Session Key The application's encryption key is used for encrypting sessions and other sensitive data. If this key has been compromised or if you just want to regenerate it as part of the upgrade, you can do so with the following command:

    php artisan key:generate
    

    Note: This will invalidate all existing sessions, so users will be logged out and will need to log in again.

  3. Verify CSRF Token Implementation Ensure that your forms include the CSRF token field. In your blade templates, you should have something like this:

    <form method="POST" action="/your-route">
        @csrf
        <!-- The rest of your form -->
    </form>
    

    If you're making AJAX requests, make sure the CSRF token is included in the headers. With Axios, for example, you can set it up globally like this:

    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
    
  4. Session Configuration Check your config/session.php file and ensure that the domain and path are correctly set, especially if you're running your application across multiple subdomains or have made changes to your environment.

  5. Middleware Order Ensure that the \Illuminate\Session\Middleware\StartSession::class middleware is included before the \App\Http\Middleware\VerifyCsrfToken::class middleware in your app/Http/Kernel.php file.

  6. Cookie Configuration If you're using secure cookies ('secure' => true in your config/session.php), make sure you're accessing your site over HTTPS, otherwise, the cookies (including the CSRF token cookie) won't be set properly.

  7. Browser Cookies Sometimes, the issue can be on the client side. Ask your users to clear their browser cookies and cache. This can resolve issues where old, invalid tokens are being sent with requests.

  8. Check Custom Middleware If you have any custom middleware that manipulates the request or response, ensure that it's not interfering with the CSRF token or session data.

If you've gone through all these steps and are still experiencing issues, you might want to check the Laravel upgrade guide for any CSRF or session changes that you might have missed, or look for any open issues on the Laravel GitHub repository that might be related to your problem.

1 like
fylzero's avatar
Level 67

@LaryAI Answer #7 turned out to be the solution. I for some reason refused to think that would have anything to do with the problem. I should have just followed all these steps more closely. Oh well. Glad it's fixed! =)

ZyadYhia's avatar

@LaryAI on laravel 11 the kernal file doesn't exist anymore so how to define the middleware and where i can find the middleware classes?

fylzero's avatar
Level 67

@ZyadYhia Middleware can now be defined in /bootstrap/app.php

Note: Using Laravel Shift is actually very worth it for the 10 to 11 upgrade, it takes care of all of this for you!

1 like
fourdee's avatar

@fylzero FWIW... anyone coming here from a 9 -> 10 -> 11 upgrade (my path -- not sure where it got messed up) My /bootstrap/app.php was old so I copied a fresh version in and it worked. I deleted app/Http/Kernel.php for good measure and it didn't do anything...

PS. I don't think it matters, but I'm using Breeze for Inertia + Vue

Tray2's avatar

Have you tried regenerating the application key?

1 like
fylzero's avatar
Level 67

@Tray2 tried all of the individual commands as well as the full php artisan optimize:clear, still throwing the error. It doesn't seem like the csrf is being passed with the request headers.

jlrdw's avatar

@fylzero Have you tried updating bootstrap app with:

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Support\Facades\Route;

return Application::configure(basePath: dirname(__DIR__))
                ->withRouting(
                        web: __DIR__ . '/../routes/web.php',
                        commands: __DIR__ . '/../routes/console.php',
                        using: function () {
                            Route::middleware('web')
                            ->namespace('App\Http\Controllers')
                            ->group(base_path('routes/web.php'));
                        },
                        health: '/up',
                )
                ->withMiddleware(function (Middleware $middleware) {
                    $middleware->group('web', [
                        \Illuminate\Cookie\Middleware\EncryptCookies::class,
                        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
                        \Illuminate\Session\Middleware\StartSession::class,
                        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
                        \Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
                        \Illuminate\Routing\Middleware\SubstituteBindings::class,
                        \Illuminate\Session\Middleware\AuthenticateSession::class,
                    ]);
                })
                ->withExceptions(function (Exceptions $exceptions) {
                    //
                })->create();


Sorry, it's formatted in IDE, couldn't get it pasted correctly.

https://laravel.com/docs/11.x/middleware#manually-managing-laravels-default-middleware-groups

1 like
fylzero's avatar
Level 67

@jlrdw Tried making these changes and nothing worked - I think the issue is that the X-Xsrf-Token request header isn't being sent. I feel like back in the day this was added in the app.js but even looking at the pre-Shifted application I can't seem to figure out where that is grabbed on the front end and passed in the request headers. Might be an issue with Inertia or axios. I don't know much about this tbh.

puklipo's avatar

Write more details.

Are you using Sanctum?

Did you change $except of VerifyCsrfToken in Laravel10?

Did you slim down when upgrading to 11?

1 like
fylzero's avatar
Level 67

@puklipo using Sanctum, Jetstream w/ Vue + Inertia, I did slim down the application, no modifications to $except.

fylzero's avatar
Level 67

I've confirmed the request header does not include X-Xsrf-Token as it does in other applications. This seems like something blew up in Axios/Javscript somewhere?

I have no idea how this is passed, even looking at other applications/the main branch of this application pre-Shift.

Update: Apparently Axios when used with Inertia removes the need for the header to be included because it does this under the hood. I am using standard axios.post calls which were working pre-Shift - even in Laravel 11 - I manually upgraded and ran the Shift specifically for slimming down the skeleton/modernizing the project.

I tried re-writing the call using router.post and still the X-Xsrf-Token is not included. I'm working on manually passing a token just to validate everything else is working. I also have another project I may run a Shift on just to see if this issue is specific to Shifting an Inertia application (which I can't imagine is the case.)

1 like
fylzero's avatar
Level 67

Further update: This works - though I don't understand why this stopped working and would vastly prefer not to have to add the token manually to each request.

app/Http/Middleware/HandleInertiaRequests.php

return array_merge(parent::share($request), [
    'csrf_token' => csrf_token(),
]);
axios
    .post('/comment', {
        ...,
        _token: usePage().props.csrf_token,
    })
gych's avatar

@fylzero Normally axios already sets the csrf token to all requests but have you tried to set the default header?

axios.defaults.headers.common['X-CSRF-TOKEN'] = add_token_here;
1 like
fylzero's avatar
Level 67

@gych I was thinking of doing this and then looked at the Inertia docs: https://inertiajs.com/csrf-protection

They specifically remove this in Laravel due to how Inertia is set up under the hood. I. also just have no idea why this would have broken with this upgrade.

fylzero's avatar
Level 67

Turned out to be an issue with Cookies. Clearing cookies and re-logging in solved the problem. It took me way too long to even consider trying this.

1 like
igorleszczynski's avatar

In my case it was problem with VerifyCsrfToken (leftover from laravel 10). In 11 version, laravel loads it automatically by Illuminate\Foundation\Http\Middleware\ValidateCsrfToken. So, i think if you have in your code VerifyCsrfToken class laravel will load it two times and something going wrong.

1 like

Please or to participate in this conversation.