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

EdwinvanDessel's avatar

Using Sanctum with a Vue SPA

Hi,

I am trying to use Sanctum in my local development environment (using Homestead). I have set up two projects:

  • An API backend using Laravel 7 (latest version) running at backend.smi.local:8000
  • A SPA frontend using Vue CLI 3 running at localhost:8080 if I compile for development and at admin.smi.local:8000 if I run a build version

I added Laravel Sanctum to my backend project using composer require laravel/sanctum, published the sanctum configuration file and ran the migration. And of course I added the middleware to Kernel.php: 'api' => [ EnsureFrontendRequestsAreStateful::class, 'throttle:60,1', \Illuminate\Routing\Middleware\SubstituteBindings::class, ],

I went through all settings needed for Sanctum:

sanctum.php

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,127.0.0.1')),

'expiration' => null,

'middleware' => [
    'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
]

cors.php

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

'allowed_methods' => ['*'],

'allowed_origins' => ['*'],

'allowed_origins_patterns' => [],

'allowed_headers' => ['*'],

'exposed_headers' => [],

'max_age' => 0,

'supports_credentials' => true,

session.php

'domain' => env('SESSION_DOMAIN', null),

And within the Laravel .env file:

SESSION_DOMAIN=.smi.local:8000
SANCTUM_STATEFUL_DOMAINS=localhost:8080,admin.smi.local:8000

Within my SPA frontend I added axios via the Vue UI as a plugin. This results in a axios.js file within the plugin folder where you can maintain all central settings for axios. The only thing I changed in the axios.js installed by default is the definitions in the config-variable like so:

let config = {
	baseURL: process.env.VUE_APP_API_URL,
	withCredentials: true,
};

In the .env.development file in this project I added:

VUE_APP_API_URL=http://backend.smi.local:8000

Within the login-function of the login form of the SPA I added this function:

axios.get('/sanctum/csrf-cookie')
    .then(response => {
        console.log(response);
    });
	

And here it goes wrong. In stead of a successful request I get:

Access to XMLHttpRequest at 'http://backend.smi.local:8000/sanctum/csrf-cookie' from origin 'http://admin.smi.local:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

or

Access to XMLHttpRequest at 'http://backend.smi.local:8000/sanctum/csrf-cookie' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

By now I have gone over all the settings about a zillion times. Tried it with and without the port-setting, with and without http:// in front of the STATEFUL_DOMAINS variable and I don't know what else but to no avail. I can't get the communication between my SPA and backend to work. I must be overlooking something but I can't seem to figure out what.

Any help would be much appreciated.

Edwin

0 likes
8 replies
EdwinvanDessel's avatar

Unfortunately, followed you tutorial, which is a pretty good and clear introduction but all settings seem to be right. It is not based on localhost but on a local .smi.local domain (backend.smi.local being the API-part en admin.smi.local being one of the frontend apps). I have configured the session domain and the stateful domains like this:

SESSION_DOMAIN=.smi.local

SANCTUM_STATEFUL_DOMAINS=admin.smi.local

But still I get this message: Access to XMLHttpRequest at 'http://backend.smi.local:8000/sanctum/csrf-cookie' from origin 'http://admin.smi.local:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

What is rong here? Any clue in hat direction I can find an answer?

Edwin

Tray2's avatar

The cors issue is what you get when using localhost. You need to use a proper domain for ajax.

nikolayandreev's avatar

For me one of the problems I had with Sanctum was SESSION_DRIVER=cookie you can try it.. Also after /sanctum/csrf-cookie request you need to make an auth request with Auth::attempt and etc.. But I supose you know that..

MaverickChan's avatar

if you have put this in kernel.php

use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;

in Session.php did you change to file?

put these 3 lines in you front end vue app.js or whatever you called it

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

and , i really don't understand why you have a file called env.development and what does it do when you change it ?

EdwinvanDessel's avatar

If you mean with 'in Session.php did you change to file' the value of SESSION_DRIVER in the config file, than the answer is yes. The values for axios are already present, but in a central file defining this for the entire application.

I have been looking at the code of HandleCors class and tracked the request of my frontend app through that class. In the first function it starts with checking whether the request should be handled by CORS. This happens in the function shouldRun(). My request passes the first check (in which is checked whether the two domains are equal) but consequently fails the second one.

In that second check a function isMatchingPath() checks if the path requested is in the list of CORS-paths. This is done by first retrieving the paths with which to match:

// Get the paths from the config or the middleware
    $paths = $this->container['config']->get('cors.paths', []);

But although I have this line in my config-file cors.php:

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

the value of $paths is only 'api/*' and as my first request goes to 'sanctum/csrf-cookie' the request is denied as a non-CORS request, no CORS-headers are added and my request fails.

But it is still unclear to me why this varaible is not filled with all the paths I listed in cors.php.

EdwinvanDessel's avatar
EdwinvanDessel
OP
Best Answer
Level 1

I guess I will never know what went wrong. My final attempt was deleting the entire backend project and build it from scratch. And know it all works as expected. Apparently I made a mistake of something went wrong in the former installation.

1 like
tenzan's avatar

@edwinvandessel I had same issue (I hope it was same...) and running following commands fixed the issue: php artisan config:clear && php artisan config:cache && php artisan cache:clear

1 like

Please or to participate in this conversation.