shadkamel's avatar

Laravel API CSRF-cookie is not set on the NextJs project

Hello everyone, i have a problem with connecting a Nextjs project to a laravel api, i did what the documentation said, and implemented all instructions but still nothing.

i the documentation it need to store a xsrf-token in the browser cookie by sending HTTP request to "/sanctum/csrf-cookie", but the browser reject it and says:

Cookie “laravel_session” has been rejected because it is in a cross-site context and its “SameSite” is “Lax” or “Strict”.

i set SameSite to null but i still get this.

note: i use laravel herd so the domain for the laravel project is diffrent from the nextjs domain, the nextjs domain is http://localhost:3000

0 likes
8 replies
LaryAI's avatar
Level 58

Certainly! This is a common issue when working with Laravel Sanctum and a separate frontend (like Next.js) on a different domain or port. The problem is related to cross-site cookies and the SameSite and Secure cookie attributes.

Why This Happens

  • Browsers block cookies with SameSite=Lax or SameSite=Strict in cross-site requests.
  • By default, Laravel sets SameSite=Lax for cookies.
  • If your API is on https://your-laravel-app.test and your frontend is on http://localhost:3000, the browser considers this cross-site.
  • For cross-site cookies to work, you need SameSite=None and Secure=true (i.e., HTTPS).

Solution Steps

1. Use HTTPS for Both Frontend and Backend

Browsers require Secure cookies for SameSite=None. So, both your Laravel API and your Next.js app must be served over HTTPS.

  • For Laravel Herd, your app is likely already on HTTPS (e.g., https://your-app.test).
  • For Next.js, you can use mkcert or similar tools to serve it over HTTPS locally.

2. Configure Laravel's config/session.php

Set these values in your config/session.php:

'domain' => '.your-app.test', // Or null for localhost, or your custom domain
'secure' => true,
'same_site' => 'none',

Note:

  • If you are using localhost, set 'domain' => null.
  • If you have a custom domain (e.g., .myapp.test), set it accordingly.

3. Configure CORS in Laravel

In config/cors.php:

'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_origins' => ['https://localhost:3000'], // Use HTTPS!
'allowed_methods' => ['*'],
'allowed_headers' => ['*'],
'supports_credentials' => true,

4. Make Sure to Send Credentials in Your Next.js Requests

When making requests from Next.js (using fetch or Axios), you must send credentials:

With Axios:

axios.get('https://your-app.test/sanctum/csrf-cookie', {
  withCredentials: true
});

With fetch:

fetch('https://your-app.test/sanctum/csrf-cookie', {
  credentials: 'include'
});

5. Restart Your Laravel Server

After changing config files, restart Laravel Herd or run:

php artisan config:clear

Summary Checklist

  • Both frontend and backend are served over HTTPS.
  • Laravel's session config: 'same_site' => 'none', 'secure' => true.
  • CORS config allows your frontend origin and supports credentials.
  • Next.js requests use withCredentials: true or credentials: 'include'.

References


If you follow these steps, your CSRF cookie should be set correctly and authentication should work! If you still have issues, double-check the browser's network tab for cookie attributes and CORS errors.

JussiMannisto's avatar

For cookies to work on cross-domain requests, you have to set the same_site config to 'None', not null. If you set it to null, the SameSite attribute is omitted from cookies, and browsers default to treating it as Lax.

Do note that if you use SameSite=None, you must also add the Secure attribute. This is the session.secure config in Laravel. It's not a quirk of Laravel, it's part of the HTML living standard. Cookies will still work over HTTP on localhost, though.

1 like
shadkamel's avatar

@JussiMannisto in the documentation it says i could be both (null, 'none'), but still not working with the 'none' too.

JussiMannisto's avatar

@shadkamel I updated my reply to mention the Secure attribute.

But like I said, null and 'None' have different meanings. Null = omit the SameSite attribute, 'None' = set SameSite to None. The latter is needed for cross-domain requests.

1 like
JussiMannisto's avatar

@shadkamel Btw, according to the spec, the correct value is 'None', not 'none'. Laravel probably capitalizes the value, and some browsers might even accept 'none', but you should still use the capitalized version for correctness.

1 like
shadkamel's avatar

@JussiMannisto thank you for you explanation, but still not working in both (none, None), but the laravel set the cookie in the laravel domain not the nextjs domain, i don't understand why.

JussiMannisto's avatar

@shadkamel Sorry, I missed that they were entirely different domains. Sanctum will not work if you have different main domains. That's because cookies are scoped to a domain, and can't be shared between unrelated main domains.

You can share cookies if your apps run on the same main domain, e.g. nextjs.app.test and app.test. You'd have to configure Sanctum to set the correct cookie domain, e.g.:

SESSION_DOMAIN=.app.test
SANCTUM_STATEFUL_DOMAINS=nextjs.app.test:3000,app.test

You can omit the port if the site runs on a standard port, i.e. 80 or 443.

You could try running the NextJS app on a .test domain to get around this issue. First add an entry to the hosts file of your OS :

127.0.0.1 nextjs.app.test

Then run the NextJS app using that host name. Alternatively, you could try running the Laravel app on localhost:80, but I've never used Herd, and I don't know if that's easy to do.

Ps. The Secure attribute in cookies might cause issues with a .test domain, though. I think it might be easiest to run the Laravel app in a localhost domain, ditching Herd if need be.

Edit. I changed my post to use the same main domain on both sites.

1 like

Please or to participate in this conversation.