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

FireNick's avatar

SPA, Sanctum {"message":"Unauthenticated."}

I already asked the same question 5 days ago on the laravel discord, but since I didn't get an answer, I'll ask again here...

discord link: https://discord.com/channels/297040613688475649/1121025726091628615

Summarized; for 2 days i was facing the problem {"message": "Unauthenticated."} when i tried to make a get request on api/user. (working on a SPA with Laravel / Vue3 / Laragon) Today i found a "solution" following: https://github.com/laravel/sanctum/issues/369

the same problem 2 years ago, also without answer here in the forum: (I assume it is about the same thing) https://laracasts.com/discuss/channels/laravel/laravel-sanctum-spa-authentication-protected-routes-return-message-unauthenticated

        'api' => [
            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            //\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

By adding EncryptCookies and StartSession i get the user data returned from api/user. (app/Http/Kernel.php) I wonder now if this is really a solution, or if i still have a wrong config somewhere. (I'm rather new with SPAs)

my env: (I like using the .test domain from Laragon)

APP_URL=http://therazorfoundation.test:8000
FRONTEND_URL=http://therazorfoundation.test:5173
SESSION_DRIVER=cookie
SESSION_DOMAIN=.therazorfoundation.test
SANCTUM_STATEFUL_DOMAINS=therazorfoundation.test:8000,therazorfoundation.test:5173

Routes/api.php:

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

bootsrap.js:

import axios from 'axios';
window.axios = axios;

window.axios.defaults.withCredentials = true;
window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
//window.axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content');

cors:

    'paths' => ['api/*', 'sanctum/csrf-cookie'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['*'],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => true,
0 likes
4 replies
LaryAI's avatar
Level 58

Based on the information provided, it seems like you are facing an "Unauthenticated" error when making a GET request to the api/user endpoint in your Laravel SPA using Sanctum for authentication.

To resolve this issue, you can try the following steps:

  1. Make sure you have properly installed and configured Sanctum in your Laravel application. You can follow the official Laravel Sanctum documentation for installation and setup instructions.

  2. In your app/Http/Kernel.php file, add the EnsureFrontendRequestsAreStateful middleware to the api middleware group. This middleware is responsible for attaching the session cookie to the request, which is required for Sanctum to authenticate the user.

'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    // other middleware...
],
  1. In your config/cors.php file, make sure you have configured the supports_credentials option to true. This allows the client-side application to send cookies along with the requests.
'supports_credentials' => true,
  1. Ensure that your frontend application is sending requests with credentials by setting the withCredentials option to true in your bootstrap.js file or wherever you configure your Axios instance.
import axios from 'axios';
window.axios = axios;

window.axios.defaults.withCredentials = true;
window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
  1. Verify that your SESSION_DOMAIN and SANCTUM_STATEFUL_DOMAINS environment variables are correctly set in your .env file. Make sure they match the domain and port you are using for your application.

  2. Finally, clear your application cache and restart your server to ensure that the changes take effect.

After following these steps, try making the GET request to the api/user endpoint again and see if the "Unauthenticated" error is resolved. If you still encounter issues, make sure to check your server logs for any error messages that might provide more information about the problem.

Note: It's important to keep in mind that this solution assumes you have properly set up Sanctum and your authentication flow. If you are still having trouble, it might be helpful to provide more details about your authentication setup and any relevant code snippets.

FireNick's avatar

Okay for those who end up here in the future, I still don't know if what I did was a working solution, since I didn't get an answer anywhere, I guess not. I've rebuilt the project several times now and with the breeze-api scaffolding it seems to work but differently than I expected.

I followed the following video with a few modifications:

https://www.youtube.com/watch?v=2zKoS8GsKK8

my .env:

APP_URL=n.test:8000
FRONTEND_URL=n.test:5173
SESSION_DOMAIN=n.test
SESSION_DRIVER=cookie

Important, if I do anything to the SANCTUM_STATEFUL_DOMAINS nothing works anymore so better leave it empty I suppose...

vite.config:

    server: {
        host: 'n.test',
        port: 5173,
    }

cors:

    'paths' => ['*'],
    'allowed_methods' => ['*'],
    'allowed_origins' => [env('FRONTEND_URL', 'http://localhost:3000')],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => true,

Kernal:

        'api' => [
            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            \Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

The rest is still the same, as I said, I simply followed the video... I guess I missed out on something somewhere, but I can't find it, however it's working now. If I find more, I'll keep telling you.

besfort's avatar

After I clicked on the link you provided to the similar issue, it was funny to see myself there :D

As far as I remember back then, this issue was only affecting local environment and it was working fine on the server. As soon as I found this out, I've fixed it on local too (can't remember exactly now) but it had to do with SANCTUM_STATEFUL_DOMAINS and Sanctum config related to the front-end hostname and custom ports locally.

Please or to participate in this conversation.