Michael Erwin
Michael Erwin

Reputation: 73

Laravel Sanctum XSRF-TOKEN Cookie not Getting Sent

I'm using Laravel 8 and I've been trying to follow the sanctum documentation for SPA authentication. I've already done setting up the necessary configurations required. The backend server is running on localhost with default port(80) while SPA client is running on localhost:3000. I'm using nuxt framework for client with axios to make a request.

The initial request should be made to /sanctum/csrf-cookie to initialize the CSRF protection cookie and here's what network traffic traffic shows

enter image description here

The second request is the actual request that should contain the cookies sent by the first request for the domain but it looks like the XSRF-TOKEN is being skipped. Here's what network traffic looks like

enter image description here

sanctum.php config file:

<?php
return [
    'stateful' => explode(',', env(
        'SANCTUM_STATEFUL_DOMAINS',
        'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1'
    )),
    'expiration' => null,
    'middleware' => [
        'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
        'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
    ],
];

cors.php config file:

<?php
return [
    'paths' => ['api/*', 'sanctum/csrf-cookie'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['*', 'localhost:3000'],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => ['XSRF-TOKEN', 'X-XSRF-TOKEN'],
    'max_age' => 0,
    'supports_credentials' => true,
];

session.php config file

<?php

use Illuminate\Support\Str;

return [
    'driver' => env('SESSION_DRIVER', 'file'),
    'lifetime' => env('SESSION_LIFETIME', 120),
    'expire_on_close' => false,
    'encrypt' => false,
    'files' => storage_path('framework/sessions'),
    'connection' => env('SESSION_CONNECTION', null),
    'table' => 'sessions',
    'store' => env('SESSION_STORE', null),
    'lottery' => [2, 100],
    'cookie' => env(
        'SESSION_COOKIE',
        Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
    ),
    'path' => '/',
    'domain' => env('SESSION_DOMAIN', null),
    'secure' => env('SESSION_SECURE_COOKIE'),
    'http_only' => true,
    'same_site' => 'lax',
];

I set this in nuxt.config.js

export default {
  axios: {
    withCredentials: true,
    baseURL: 'http://localhost/',
  },
}

Can somebody tell me why the XSRF-TOKEN cookie is not getting sent back?

Thanks

Upvotes: 0

Views: 8239

Answers (4)

Feras Jobeir
Feras Jobeir

Reputation: 36

Probably your laravel app is running on 127.0.0.1:8000 and your SPA is running on localhost:3000 or localhost:8080 etc.

Make sure that you:

  1. Set the session domain to localhost
  2. Set the supports_credentials to true (cors.php)
  3. Set with_credentials to true in your client
  4. When you send requests to your backend, send it to localhost:8000 instead of 127.0.0.1:8000

Upvotes: 0

Svetoslav Stefanov
Svetoslav Stefanov

Reputation: 111

If you followed these guides and you're still having problems, as I did, you might have missed setting SESSION_DOMAIN in your .env file.

Open Laravel's .env file and add SESSION_DOMAIN=.localhost

One more thing: If you cannot access "/csrf-cookie" route for some reason and still need to call "sanctum/csrf-cookie/", but Axios is adding /api in front of your requests, then use this piece of code:

let myNewInstance = this.$axios.create({
   baseURL: 'http://localhost' //without /api at the end
});

myNewInstance.get('/sanctum/csrf-cookie');

Upvotes: 0

Michael Erwin
Michael Erwin

Reputation: 73

Turns out the problem was caused by nuxt configuration for axios module. I just replaced the field 'withCredentials' with simply 'credentials'.

This is now the updated nuxt.config.js:

axios: {
    credentials: true,
    baseURL: 'http://localhost/api/',
  },

Upvotes: 5

Nick Dawes
Nick Dawes

Reputation: 2244

Here's my Nuxt/Laravel 8/Sanctum config.

Notice I've not included 'sanctum/csrf-cookie' in 'paths', because I've changed the prefix for Sanctum in sanctum.php. I've also got my nuxt dev server on port 3050, which is what you'll see in my config. Change yours to suit (e.g. 3000).

cors.php

'paths' => ['api/*'],
'allowed_methods' => ['*'],
'allowed_origins' => [env('ALLOWED_ORIGINS')], 
    .env e.g.: ALLOWED_ORIGINS=http://localhost:3050
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,

Everything in session.php is left default, but make sure you update your .env with the correct SESSION_DOMAIN.

session.php

'driver' => env('SESSION_DRIVER', 'file'),
'lifetime' => env('SESSION_LIFETIME', 120),
'expire_on_close' => false,
'encrypt' => false,
'files' => storage_path('framework/sessions'),
'connection' => env('SESSION_CONNECTION', null),
'table' => 'sessions',
'store' => env('SESSION_STORE', null),
'lottery' => [2, 100],
'cookie' => env(
    'SESSION_COOKIE',
    Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
),
'path' => '/',
'domain' => env('SESSION_DOMAIN', null),
    .env e.g.: SESSION_DOMAIN=localhost
'secure' => env('SESSION_SECURE_COOKIE'),
'http_only' => true,
'same_site' => 'lax',

Everything in sanctum.php is default, make sure you enter the correct SANCTUM_STATEFUL_DOMAIN in your .env (example below). I've also added the line 'prefix' => 'api'. This allows me to set a single baseURL in axios and call the csrf-cookie route via http://localhost:3050/api/csrf-cookie. See more about it here.

sanctum.php

'stateful' => explode(',', env(
    'SANCTUM_STATEFUL_DOMAINS',
        .env e.g.: SANCTUM_STATEFUL_DOMAINS=localhost:3050
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1'
)),
'expiration' => null,
'middleware' => [
    'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
    'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
],
'prefix' => 'api'

Then on the frontend, I have set axios up with a baseURL and ensured withCredentials is set to true

axios.defaults.withCredentials = true;
axios.defaults.baseURL = process.env.API_BASE_URL;
    .env e.g.: API_BASE_URL=http://localhost:8000/api

Assuming you've made no other changes that contradict the settings above, this should work :)

Upvotes: 1

Related Questions