Search code examples
postmanlaravel-sanctumlaradocklaravel-11

Sanctum API: 419 CSRF token mismatch with laradock


I created a project in Laravel 11 with Laradock in multi-project and thus defined the host in the hosts file:

127.0.0.6 laravel.api.test

config/cors.php

return [
    'paths' => ['api/*', 'sanctum/csrf-cookie', 'auth/*'],

    'allowed_methods' => ['*'],

    'allowed_origins' => ['*'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => true,
];

bootstrap/app.php:

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__ . '/../routes/web.php',
        api: __DIR__ . '/../routes/api.php',
        commands: __DIR__ . '/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->statefulApi();
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

routes/web:

Route::prefix('auth')->group(function () {
    Route::post('/login', LoginController::class);
});

.env:

SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=.api.test

SANCTUM_STATEFUL_DOMAINS=laravel.api.test

then I call this route in POST with postman :

http://laravel.api.test/auth/login

as parameters in the header step:

Accept:application/json
X-CSRF-TOKEN:{{xsrf-token}}

and in the Pre-request-script section:

pm.sendRequest({
    url: "http://laravel.api.test/sanctum/csrf-cookie",
    method: "GET"
}, function (err, res, { cookies }) {
    if (!err) {
        console.log('xsrf-token', cookies.get('XSRF-TOKEN'))
        pm.globals.set('xsrf-token', cookies.get('XSRF-TOKEN'))
    }
})

I get the following error 419:

{
    "message": "CSRF token mismatch.",
    "exception": "Symfony\\Component\\HttpKernel\\Exception\\HttpException",
    "file": "/var/www/laravel_api/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php",
    "line": 633,
    "trace": [

LOG POSTMAN

GET http://laravel.api.test/sanctum/csrf-cookie 204 42 ms

xsrf-token

eyJpdiI6IlZDSis1d2kyR0lXWWdWc2VEeEV3MGc9PSIsInZhbHVlIjoiZ3htNlBaYXlwL2d0dlBITXpGZVp3ejN4V1NGYm5iK21EWGI1dFZObEZlNmhRZ1UrWXVLUlk0SmhPckZ4YUdJUjZuK3hBcVl4YkpDZnNKMisyRmQyYkhITlBVblhjdWxpdU92aFc4NU5MOTVYSWIzTE1wU3dOVzFCTXJMMGt3UDEiLCJtYWMiOiI0NWNiOTY4MWRhZjdjYmNhNjQyMjY5MGQzMGQ5MzYxZWFjNjljODIzYmQ0NDUwNzUwNjQ1MmEwNzI0NGI3ZDcyIiwidGFnIjoiIn0=

POST http://laravel.api.test/auth/login

419
75 ms
Network
Request Headers
Accept: application/json
X-CSRF-TOKEN: eyJpdiI6IlZDSis1d2kyR0lXWWdWc2VEeEV3MGc9PSIsInZhbHVlIjoiZ3htNlBaYXlwL2d0dlBITXpGZVp3ejN4V1NGYm5iK21EWGI1dFZObEZlNmhRZ1UrWXVLUlk0SmhPckZ4YUdJUjZuK3hBcVl4YkpDZnNKMisyRmQyYkhITlBVblhjdWxpdU92aFc4NU5MOTVYSWIzTE1wU3dOVzFCTXJMMGt3UDEiLCJtYWMiOiI0NWNiOTY4MWRhZjdjYmNhNjQyMjY5MGQzMGQ5MzYxZWFjNjljODIzYmQ0NDUwNzUwNjQ1MmEwNzI0NGI3ZDcyIiwidGFnIjoiIn0=
Content-Type: text/plain
User-Agent: PostmanRuntime/7.37.0
Postman-Token: 7ff581ea-e9b2-4b69-8423-a7c9ff349e83
Host: laravel.api.test
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 60
Cookie: XSRF-TOKEN=eyJpdiI6IlZDSis1d2kyR0lXWWdWc2VEeEV3MGc9PSIsInZhbHVlIjoiZ3htNlBaYXlwL2d0dlBITXpGZVp3ejN4V1NGYm5iK21EWGI1dFZObEZlNmhRZ1UrWXVLUlk0SmhPckZ4YUdJUjZuK3hBcVl4YkpDZnNKMisyRmQyYkhITlBVblhjdWxpdU92aFc4NU5MOTVYSWIzTE1wU3dOVzFCTXJMMGt3UDEiLCJtYWMiOiI0NWNiOTY4MWRhZjdjYmNhNjQyMjY5MGQzMGQ5MzYxZWFjNjljODIzYmQ0NDUwNzUwNjQ1MmEwNzI0NGI3ZDcyIiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6ImRyUGh2ZklLUFhYbCtwTnpqSWZ0SHc9PSIsInZhbHVlIjoiQ1BJbGloZGhPYmlKTlpTSHIxZjNTQVhEQkpER210NWlhdlpwVUN3OFJkTkJ5UmdKWVpZOVNybE9uV2NaTWtiNGZCZnEzanpRNi81T08zOE43ME9pTnhhMmJScEhDc1hXeGc0emJnQUl2VjgvZXd3a0NneU9xZm9nYTljblllb0YiLCJtYWMiOiIwMDVmYzM0ODcwZmZlMTU3OWJhYTJjNjhlOTAxNzE4OTFlMDI4OGQ1Y2ZhNWUxZWJhNTBjY2E2Y2RlOWI2ODEzIiwidGFnIjoiIn0%3D; tC8zpXwRJnmAZKHQkeY1sldxapFyUQ545wEeOmLq=eyJpdiI6IjNadzNiT1RHVXF3WlUwR3Z6UUJaTnc9PSIsInZhbHVlIjoiTEpLeXg0eDJ6MkFLMGhXN0t6Vy9sT2FPZGtmTkR5MFpKYXE2MlNxdlZWVjc5dGt3enk5Y21FOUIvNjIrZUxUcUlmZHVFYkEyNDdPLzBKWWlRYnVtMUFXekhLMWF2SnlxSDNwWHFhbVdMdFRZb1haSXdxYlpFQ21jZUJsT2hKb2xXZGNRTVVpYWUxZU5aYlJLUldnOU8xMkd4NHdQaE0xVkxWbGxhQTh0SlUrNHJSWlNadHJmTTBIbnA5cTZvSE45anhNaXFaeEh1SkVqUnVsMS9uVHhCaGNrR3E1M2NGdG9rNjJzLzFrM21TKzFYRlY3eGd6dEswZHhoNjUxNXhOTVozMDNoUmhXSkd6cmFONkx5NjJROU44bzc0Mk03YTRCWEFRaEZGWDdtOHQ2SnhLd3NsWHFTaUIzSzk2VkpTSTViNXVCSHVhVVJSdVc2SDBrSEVFZER4RDFzak1sZFpRVHpyeVdZUzlEZHNFRW0wVk4xUXFwN2F1bVRZZjhhWUw1VWhXTEszMjVwMlE2eXpDbTRIT3ptZHVuUWRYYVg1eDBGL0RVelFvSDFjN0REcTJHcnZWdDFrTjcycmhwTnJRRDM5UWlTZUJmS2ZtenJpU3BXVDFxWU84bXRzOVQ0TUdoMUxSdmtoRnhZOHF1Q1pvSzlqQTNGT3hERXdkbU5menY5VGlXcXgyZzJ2OTFxL3I3VCtuMHRoSkllZFdBa1Q5cjhPdnQ2aSsxNVljTEUwNWt5eDNKL1Bpb1NZMEZwWnFHS25NR05OOUVjcm40Wi9xUTY3N3Z0bk5RRjF1RFdOdXVUOHBhZENxRDZSM0JNSHcyRVpGMjAxVjN2K215OFR5UHM2YjNPRjNQRFR0MFVEYlFnQm5HZWVBMFpRUXpQVElyYjVOdkEwLzBQWEtkS1NUTUI3MmYxSm5LSVBsaW9rUTVFNlRpVlprd1BCK3N5ejhqeGd6UHBhc1M5Znh5TGp2N2Z6Z25yZmtLcWF0b09SYzhRWklmVlkzcEJQWGFUUkxlT20wS2NMUVVsTldUVm1PWnNidXZjclJ4aWJpM3JEelBqaFh1REVVWGIzN0k1NTRBdnhlS1NYZDE0VW5oTW1IQklCYWF6R0pOakhhSEZOVmJudzF3ZlB6Z0ZMNWlTQ0dEMnJ5OXRrZ3dRT0k9IiwibWFjIjoiNDA3MzhlMzM1ZjZkMGI5MTUwZGE5OTc0MDQ5NDlkZGRmNmRmZTg3ODU2ZWFhZjBmZDIzMzEwYzk4NTA0YzFmOCIsInRhZyI6IiJ9
Request Body
Response Headers
Server: nginx
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/8.3.4
Cache-Control: no-cache, private
Date: Thu, 04 Apr 2024 10:36:55 GMT
Vary: Origin
Set-Cookie: laravel_session=eyJpdiI6ImVodzRoUHFZN25qWTZTU0h3QmRPanc9PSIsInZhbHVlIjoieThJUnE5L1lkRFdBK3NQSTlubzJOUFVSVjA5V2RvTkVtSnBXL25Md3ZWWEJ4Q2xRT3RuTXhqMGhaamdjK1JqL3N5SGV5MDdkMzZURW85SUkxbW1GUS9mdTdoRGllMTJVeGN6cVk3bTBiSlA4dUpYQUtZeDBFWXg4cmtLeEdKL3EiLCJtYWMiOiI2MTRmYTdhMTQ3MmFmNzhkODczYzZkNjhiMGE2NGE5YjBhYWE2NDkzZGMyZTliZDk1OTI0MDVkZWE1YTUxYTgzIiwidGFnIjoiIn0%3D; expires=Thu, 04 Apr 2024 12:36:55 GMT; Max-Age=7200; path=/; domain=.api.test; httponly; samesite=lax
Set-Cookie: tC8zpXwRJnmAZKHQkeY1sldxapFyUQ545wEeOmLq=eyJpdiI6Imx2eTBWTW9HaHBiWFRhRHpuODJRR1E9PSIsInZhbHVlIjoiZzVCSGpqbVpzVmpXVjVuMnlRL29jMEx4dURiUElaVmc2U3BYaEkyUjJvZ29oY056NTNxd2NtQmdQakxvOW93VlRXTTM1Vks4S2pmdGNaWlk5RWw2NWFUL3RsK1hWekJkZHV3YW9KVlZZbHkrQ1BqZmlQM0ZnMHp2emwvZCtEcVcwd2QzNVNXWHRndHpCZkdYUFJjWG4zUTl3bDNMajcvVElPdjFXWEFQMXVwbjlEcTNNSDR6ZEJ5QnY2NCtuYm5wTWhxZ1RXc0RZYWtVVE1yQmJUWDVwZktEdWdRclM4SjB2QXgzcGtpK2RFaVQzN2VnR1lVY055N0p1SDAxSGNGY09RY0RVUjNXallDOGFFVTU0aktxcWdhcHZMZThyTXJaU2xYZHV1RjZFVkwxVFhmMjR3T0ZkQ1FqNDA3K1lmQUh0VnZHNGkyNG1SRTFhM3g0akIvNFFKR0pIQUpobHNXWVhrdjhnZHl4SXpTMFBUYVRMaEpqR09Eakl1UzNEdE8weG1nRkFLRjM0RkFQMGUzOXI4UXRBMGoxRW9uQms0cWg4WFNGZnZWakZwckJpNG85Y3hKeWhoc3h3S1ltb3h6VzNPaHpCUlFkVDdxeDVOR2h1VnF0M2Z3RU1kVytoU1BIT2RrR3lOS2NLdUtRT1IyV0N1UUZlWndka0hXNm5xZThDY3dwZE9jb0phWWtwK0cwa05sWXhMbmxZK0pIM21BZk4rUUQzZjdUWTJ6cnJMdnRoeXcyQWU3Y0Z5TE5mSy8xWk41TWROTmZ1SktEMDhQM1paZGF4Wnk0ZUtWU2pDcG9KN08xVjZLNWw2NENVc0Q2ajdoVnd3Qks0UlZoT2R1VjNzeWszYmdYYjYyaEhFR3M1YjJFa3RtTFQ2d2JPbFZENG9FSTBZTjQ3cTEwNDJVKzJsQ2thTzI0RDkxZTJLU2xiZVBqbWJROVJJUm9FUE1OajBkNmxGaFFMUHBYQy9vS1Avd3lJUnVaYnVxWkJsQ0JRUFN0amRpNmVqMkZITGlDZjN3WGpwMU1NelNDaWhiUDc3c0tSSVBaV0tTbjBRbEFWdWttRklBQ2oyNkxlU1ZNbm02VTdqZTVDaTRTS1Z0SWZqbjI3NSsvYk40aUhpYnBwbjY2V01GMVM5NHBjZ2hiUkhFMld3TUQ4OVU9IiwibWFjIjoiZmU4NDQ4YzBiYTJmNmJjNGUzY2JjZTFjZWU3YWVhZjBlYTMzNDA1YWJhMzMyODViZTA4YjViMmU5OTJhYTBlMyIsInRhZyI6IiJ9; expires=Thu, 04 Apr 2024 12:36:55 GMT; Max-Age=7200; path=/; domain=.api.test; httponly; samesite=lax

Solution

  • I solved it by changing the pre request script:

      pm.sendRequest({
        url: "http://laravel.api.test/sanctum/csrf-cookie",
        method: "GET"
    }, function (err, res, { cookies }) {
        if (!err) {
            const xsrfToken = cookies.has('XSRF-TOKEN') ? cookies.get('XSRF-TOKEN') : null;
            if (xsrfToken) {
                // Add X-XSRF-TOKEN to the header of the subsequent request
                console.log('xsrfToken', xsrfToken);
                pm.request.headers.add({ key: 'X-XSRF-TOKEN', value: xsrfToken });
            } else {
                console.error('XSRF-TOKEN not found in cookies');
            }
        } else {
            console.error('Error fetching CSRF token:', err);
        }
    });
    

    the problem was the token encoding problem with postman and insomnia so I managed to solve it.