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

DrewB's avatar

Laravel 12, Vue, axios, and Sanctum ... auth issues (401) [SOLVED]

I'm trying to get vue + axios to connect with my Laravel 12 backend. I've tried to follow documentation and can login and request data. As soon as I try to wrap my non-public api routes with auth:sactum, I get errors.

I have configured in my .env: SANCTUM_STATEFUL_DOMAINS=http://localhost:5173

This stops CSRF complaints.

I can see axios sending an X-Xsrf-Token header in the requests, but alas, Sanctum is denying them with 401's.

I can also see that the request headers include referrer and origin, my cookie with both my session ID and xsrf token, etc.

My protected api routes are in a routeGroup... ''' Route::group(['middleware' => ['auth:sanctum']], function() { Route::get(... '''

A lot of documentation suggests X-Csrf-Token (rather than -Xsrf-).

I'm not sure why this has to be made so difficult.

0 likes
15 replies
DrewB's avatar

Also, here is my middleware setup:

    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->append(StartSession::class);
        $middleware->api()->statefulApi();
        $middleware->api()->remove(ConvertEmptyStringsToNull::class);
    })
JussiMannisto's avatar

401 is an authorization error, it's not related to CSRF.

Just to be clear: are you implementing a pure SPA without Inertia? An SPA will be more complicated since you'll be developing the front and back ends separately.

Are you actually serving the app from port 5173? Have you made any changes to other .env values such as SESSION_DOMAIN or FRONTEND_URL?

Are you fetching a CSRF token (e.g. from a dedicated /token route) before making requests to CSRF-protected endpoints?

DrewB's avatar

I'm not using inertia. From my composer.json:

    "require": {
        "php": "^8.2",
        "laravel/framework": "^12.0",
        "laravel/sanctum": "^4.2",
        "laravel/tinker": "^2.10.1"
    },
    "require-dev": {
        "fakerphp/faker": "^1.23",
        "laravel/pail": "^1.2.2",
        "laravel/pint": "^1.13",
        "laravel/sail": "^1.41",
        "mockery/mockery": "^1.6",
        "nunomaduro/collision": "^8.6",
        "phpunit/phpunit": "^11.5.3"
    },

To serve, I run "composer run dev". This brings up the php server on :8000 and the node server on :5173. FRONTEND_URL I did not change. SESSION_DOMAIN is localhost. Before I changed that it was "null". No difference.

I can see that in axios.defaults I do have withCredentials = true. Nonetheless, although I have a valid session, it seems to be ignored by the server.

JussiMannisto's avatar

@DrewB The Node server runs on 5173? That port is usually for the Vite server. What URL do you use to open the site in the browser?

The Axios default config should also include withXSRFToken = true.

DrewB's avatar

127.0.0.1:8000 to open in browser.

127.0.0.1:5173 is the sanctum stateful domain to stop CSRF failures.

DrewB's avatar

Hmm, I tried :8000 and I'm also not getting CSRF failures. This is really the shotgun approach.

JussiMannisto's avatar

@DrewB A couple of things:

  1. 127.0.0.1 and localhost are different origins. You have to access the site via http://localhost:8000 if you're using localhost in the stateful domain settings.
  2. Since you're accessing the app via port 8000, you must add localhost:8000 to the list of stateful domains. Otherwise sessions will not work as cookies from localhost:8000 are ignored during authentication.

So add:

SANCTUM_STATEFUL_DOMAINS=localhost:5173,localhost:8000

And access the site using http://localhost:8000.

DrewB's avatar

I tried this:


SANCTUM_STATEFUL_DOMAINS=http://localhost:8000,http://127.0.0.1:8000,http://localhost:5173,http://127.0.0.1:5173

Still, no luck. 401 error unauthorized.

I still think that I'm not getting correct session data for authentication.

Glukinho's avatar

@DrewB Shouldn't SANCTUM_STATEFUL_DOMAINS be in format host:port, without http://?

DrewB's avatar

I've read protocol makes a difference, but I'll try it.

DrewB's avatar

So, I've traced this down to a session cookie issue.

When I log in (via axios) I can see Auth::user() is correct. I also log the session id.

In subsequent axios requests, the session id is different and, if I'm using auth:sactum on the route, the request fails as 'unauthorized'.

If I remove the auth:sanctum middleware, the request succeeds.

Why would the session id change? (I'm not regenerating it)

JussiMannisto's avatar

@DrewB The session ID would change because something in your stateful API configuration is wrong, and your cookies aren't considered for authentication. Most likely culprit is the SANCTUM_STATEFUL_DOMAINS environment variable. It should list domains, not URLs with protocols.

DrewB's avatar

I never got this sorted out, so I switched to using 3rd party Bearer tokens. Took no time.

Please or to participate in this conversation.