8

So it's been several hours I couldn't figure out the issue even reading through and trying any possible solution available on the internet. I'm using Laravel 7.x with Vue js and struggling with Sanctum SPA authentication.

Login request works fine which is using Auth::routes() defined in web.php

enter image description here

but, any requests made to APIs defined in api.php under auth:sanctum middleware returns 401. For example, call to fetch the user object fails with status 401:

enter image description here

Here is the Request Header:

enter image description here

This is web.php

enter image description here

This is api.php

enter image description here

Here is the stateful object in sanctum.php

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

On vue.js side, I've set the withCredentials flag to true:

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

window.axios.defaults.withCredentials = true;

in cors.php, suports_credentials flag is also set to true

enter image description here

and, here is my Kernel.php

/**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            EnsureFrontendRequestsAreStateful::class,
            'throttle:60,1',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

Zee
  • 381
  • 2
  • 11
  • what is the `EnsureFrontendRequestsAreStateful::class` and why is it in the Kernel file namespace ? Since you want statefull sessions, why not use the `web` group instead of the `api` one ? if it is juste for the prefix `/api` in the url, you can change that even using `web` group. – N69S Jun 13 '20 at 03:31
  • I'm following the Laravel documentation for Sanctum SPA authentication. See https://laravel.com/docs/7.x/sanctum#spa-configuration – Zee Jun 13 '20 at 15:09
  • 1
    did you find a solution? I followed the instructions stated in laravel.com/docs/7.x but the instruction they given was limited. – asela daskon Sep 23 '20 at 14:43

2 Answers2

13

I had the same issue and I couldn't find any answer but after troubleshooting I got it working.

Your issue is that you're accessing it through localhost port 8000, but in your stateful param under sanctum config there is no localhost:8000 (even localhost pointing to 127.0.0.1). The config uses $_SERVER['SERVER_NAME'] so it actually looks for the exact content while accessing it.

A simple fix below:

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', implode(',', [
    'localhost',
    'localhost:8000',
]))),
  • Thank you so much, Icaro. This had me scratching my head whole day. Such a silly thing, but I think it should be mentioned somewhere in official docs too. – Pratik149 Jun 18 '20 at 20:58
  • 3
    Icaro has the answer, however, you should add it to your .env file as `SANCTUM_STATEFUL_DOMAINS="localhost:8000"` Instead of the `sanctum.php` file – BustahBoi Jul 27 '20 at 20:41
  • @aseladaskon can you elaborate which package versions, urls/ips are you using? – Icaro Scherma Sep 28 '20 at 17:23
  • hello Ícaro R. Scherma, I decided to skip this authentication package. I'm using spatie package. – asela daskon Sep 28 '20 at 17:36
-1

I not use Sanctum but use Vuejs Laravel and Axios and I notice that you need to add to all axios protected URL the header Authorization

Bearer YOURTOKENKEY

On my ap.js I use

import jwtToken from './helpers/jwt-token'

    axios.interceptors.request.use(config => {
        config.headers['X-CSRF-TOKEN'] = window.Laravel.csrfToken
        config.headers['X-Requested-With'] = 'XMLHttpRequest'

        if (jwtToken.getToken()) {
            config.headers['Authorization'] = 'Bearer ' + jwtToken.getToken()
        }

        return config;
    }, error => {
        return Promise.reject(error);
    });

and my JWTTOKEN js file

export default {
    setToken(token) {
        window.localStorage.setItem('jwt_token', token);
    },
    getToken() {
        return window.localStorage.getItem('jwt_token');
    },
}

So all request by axios send Authorization header with Bearer + token

I hope this help you

Diego Cortés
  • 427
  • 2
  • 5
  • 11
  • It's a stateful session way and X-CRF-TOKEN is automatically sent. See https://laravel.com/docs/7.x/sanctum#spa-configuration – Zee Jun 13 '20 at 15:11