suben's avatar
Level 1

Laravel Sanctum 401 Unauthorized in production only

Hey there!

I'm using Laravel 7 and the SPA authentication variant of Laravel Sanctum (CSRF tokens).

I've managed to make it work locally but when I login on my production site, any requests on my API route will result in 401 Unauthorized.

The funny thing is, that the login route authenticates me. There is no issue with that.

Also I checked, if my website or domain is stateful. (dump & and die in EnsureFrontendRequestsAreStateful class). Yes, it is stateful.

Let's assume for my configurations, that my domain is the following: mydomain.mycompany.dev

Login Logic

    public function login(Request $request)
    {
        $request->validate([
            'email' => 'required|string',
            'password' => 'required|string',
        ]);

        $isAuthenticated = Auth::attempt([
            'us_email' => $request->email,
            'password' => $request->password
        ], $request->filled('remember'));

        if ($isAuthenticated) {
            $request->session()->regenerate();

            return new Response('', 200);
        }

        return new Response('Unauthenticated', 401);
    }

My configurations

env

SANCTUM_STATEFUL_DOMAINS=mydomain.mycompany.dev,localhost,127.0.0.1
SESSION_DOMAIN=mydomain.mycompany.dev
SESSION_DRIVER=cookie
SESSION_LIFETIME=120

session.php

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

'secure' => env('SESSION_SECURE_COOKIE'),

'http_only' => true,

'same_site' => 'lax',

sanctum.php

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

'expiration' => null

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

If this is somehow relevant, the website uses the HTTPS protocol.

This has been included in the Kernel.php file too

use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;

(CORS is configured aswell!)

My question is: Why does it work locally but not on my production site?

Thanks for any help!

0 likes
18 replies
ovrdrv3's avatar

Any updates to this? I am in the same boat as you. Thanks!

AmirrezaN's avatar

Any update on this? I have exactly the same issue. Dive deep into sources. No frontend issue, no cors or cookie domain issue. The frontend domain is considered as stateful (same as OP) however, sanctum.guard ('web' by default) retrieves nothing!

AmirrezaN's avatar

Aaaaaah! Turns out that I was clearing my frontend cookie/storage (spa.example.com) but not the backend's (api.example.com) during my tests 🤦‍♂️

2 likes
gmxtrr's avatar

And how to clear it, can you please tell me what is the reason exactly ? i am tired of it

tichasmt's avatar

Did you solve the problem ? Now i stucked in this problem too

Minia's avatar

Add this in .env file (localhost)

SESSION_DRIVER=cookie 
SESSION_DOMAIN=localhost    
SANCTUM_STATEFUL_DOMAINS=localhost:8080(port number you use)
2 likes
jlmmns's avatar

My fix was to specify my default Auth Guard in /config/sanctum.php, since I was using my own, instead of "web".

tonynnabs's avatar

So I moved my login and logout routes out of api.php to web.php and that worked for me

4lmolly's avatar

2 years after, 10k people view this and there's no single solution to this. I'm currently experiencing this and I can't seem to find any solution to this on the internet. My apps work fine locally but when I deploy to production (I'm using docker btw) I get authenticated because it gets the CSRF token I could get the cookies from the browser but It can't subsequently make requests to any route that requires a CSRF token.

2 likes
ethor88's avatar

When my environment file was created in production, my APP_URL variable was set to localhost. I changed it to my production website URL and that solved things.

Keisto's avatar

I had this issue with Postman in production. The reason was the Referer header.

When accessing my site through the web referer === origin https://mysite.com so I had no issues there.

However in Postman I was talking to my backend directly https://api.mysite.com thus I have to update the referer for postman only to use https://api.mysite.com

mrmusic's avatar

I have been looking for a solution to my problem for a long time.

I ran the server on localhost:8000, SPA ran on the same port and domain.

All that had to be done was to rewrite the paths from 127.0.0.1 to localhost everywhere

lcf8381595's avatar

any update? same issue here.. work well for localhost, but 401 in production.

lcf8381595's avatar

Finally fixed the issue. For someone may has same issues as mine. Set the env like below will work:

SANCTUM_STATEFUL_DOMAINS="www.XXX.com"
SESSION_DOMAIN=".XXX.com"

so SANCTUM_STATEFUL_DOMAINS should be your Front-end URL. BUT make sure that with or without "www" before the domain name depend your front-end domain setting, if your front-end site is using www url, and you set SANCTUM_STATEFUL_DOMAINS without www, then it will cause 401 Unauthorized error.

SESSION_DOMAIN is the root domain, make sure you add a "." before the domain name.

Hope that helps.

1 like
Mrtvac's avatar

@lcf8381595 That's correct so to be safe you can add both domains (with a and without "www")

SANCTUM_STATEFUL_DOMAINS=www.XXX.com,XXX.com
SESSION_DOMAIN=.XXX.com
1 like
nestorcarvallo's avatar

@lcf8381595 My situation is similar. It works locally, but in production I get a 401 error. The production server host is an IP with a certain port. There is no communication with a front end. Do you know if the solution is through Laravel or through headers or something else on the server? Thank you very much!

Please or to participate in this conversation.