Reputation: 73
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
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
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
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:
supports_credentials
to true
(cors.php)with_credentials
to true
in your clientUpvotes: 0
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
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
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