vue-cli frontend not setting CSRF cookie from Sanctum - vue.js

I am developing a new frontend using Vue to access my existing Laravel 7 app, which uses Sanctum for authentication.
The frontend sits on app.example.com, with the backend being moved to api.example.com. The CORS middleware and Sanctum are properly configured to allow app.example.com, and so far so good.
The GET to /sanctum/csrf-cookie looks fine, however, it doesn't seem to be actually setting the cookies, causing the subsequent request to the API to return a 419.
const config = { withCredentials: true };
const api = process.env.NODE_ENV === 'production' ? 'https://api.example.com' : 'http://localhost:9000';
axios.get(api + '/sanctum/csrf-cookie', config)
.then(() => axios.post(api + '/login', data, config))
.then(response => response.json())
.then(response => { console.log('json', response); });
Console log:
Response headers from /sanctum/csrf-cookie:
No cookies are listed in devtools:
UPDATE 1: Didn't notice this earlier; the warning icons next to each Set-Cookie in the response headers display "This set-cookie's Domain attribute was invalid with respect to the current host url."

Short answer: Ports should not be specified in cookie domain attributes.
Long answer: Laravel Sanctum uses the VerifyCsrfToken middleware to both send and verify the CSRF token, which uses session config values when adding the cookie to the response:
protected function addCookieToResponse($request, $response)
{
$config = config('session');
if ($response instanceof Responsable) {
$response = $response->toResponse($request);
}
$response->headers->setCookie(
new Cookie(
'XSRF-TOKEN', $request->session()->token(), $this->availableAt(60 * $config['lifetime']),
$config['path'], $config['domain'], $config['secure'], false, false, $config['same_site'] ?? null
)
);
return $response;
}
In config/session.php:
'domain' => env('SESSION_DOMAIN', null),
In .env:
SESSION_DOMAIN=localhost:8080
Cookies on the same host ARE NOT distinguishable by ports. Because I had specified the port in the cookie domain, the browser had flagged the cookie as having an invalid domain. Removing the port did the trick.

For me to solve the problem I changed my vue cli host which was 127.0.0.1:8080 to localhost:8080 in browser,and within axios the base url is now http://localhost:7000 which is for laravel api.
after that I then set SESSION_DOMAIN=localhost in .env laravel

Related

Heroku Express / Nextjs client cookie not being set

So I'm having a bit of an issue where I have two apps hosted on Heroku the first being an Express application with the following cookie settings
const cookieSettings = {
maxAge: expiryTime,
...cookieOptions || {},
// For security these properties should always remain below the spread
httpOnly: true,
secure: process.env.NODE_ENV !== "development",
sameSite: "none",
path: "/",
}
And a Nextjs app which has some middleware that uses the cookie for login control to protect routes.
Locally I have no issues with the following login logic within the login route which sets the cookie browser side
const cookie = getCookie({ tokenOptions: { id: user._id } });
res.setHeader("Set-Cookie", cookie);
return res.sendStatus(200);
I have read there is issues with Heroku as it's on the public list of domains so the browser wont set if it comes from this but the issue I'm having is on a custom domain. My domain is https://www.mydomain.co.uk but for some reason I can't get it to set when I'm on this domain.
When using Postman I do get the cookie back but the domain comes from my API domain ie api.reviewcircle.co.uk which I think is why the browser isn't setting the cookie as the domains don't match but I can't find any info on how to fix this so would be great if anyone has any ideas.
You can see the cookie is included in the response but isn't set:

Browser fails to set cookies even with Set-Cookie response header

I am trying to get my Express backend to set a site-wide cookie on my NextJS frontend, each of which is running on separate virtual machines. The relevant backend and frontend configurations are:
In the frontend, I initate the following HTTP request:
fetch('http://192.168.1.<Express virtual machine>:3000/service', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({...}),
credentials: 'include'
}).then(res => res.json()).then(data => {console.log(data)});
In the backend, the following Express application is running with a global CORS middleware configured:
app.use(cors({origin: 'http://192.168.1.<Frontend virtual machine>:3000', credentials: true}));
app.post('/service', (req, res) => {
res.cookie('token', token, {
secure: false,
httpOnly: false,
sameSite: 'none'
});
res.json({...});
});
Upon initiating the HTTP request to /service, the Cookies section of my frontend application in the Storage (Firefox) or Application (Chrome) tab shows that there are no cookies set. However, in the network tab, the Cookies tab on my HTTP request shows that there is both a response cookie and a request cookie. The response cookie has path property set to '/' suggesting that it should have been set site-wide.

get CORS problem when ty to get a token in keycloak with vuejs and axios

I trying to access one keycloak with axios in my vuejs app, but I receive the cors error, can someone help me please? (If I make a post from POSTMAN to my keycloak works fine)
I using this code:
const params = new URLSearchParams();
params.append("grant_type", "password");
params.append("client_id", "notas-front");
params.append("username", usuario.value);
params.append("password", password.value);
console.log(params);
const config = {
// withCredentials: true,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
};
axios.defaults.headers.common["Access-Control-Allow-Origin"] =
"http://localhost:8080";
axios
.post(
"http://localhost:8082/auth/realms/lumera/protocol/openid-connect/token",
params,
config
)
.then((response) => {
console.log(response);
});
and get this error:
but when I look the request I can't find the error:
the OPTIONS returns 200
but the POST dont
Postman doesn't care about Same Origin Policy, browser do. That's why your request is working in Postman but not in the browser.
Access-Control-Allow-Origin is a response header, you can't set it on the client request. And as you can see from the OPTIONS response headers your server is returning: Access-Control-Allow-Origin: http://localhost:8080
In a development environment the best way to solve this is setting a proxy in your vue configuration. Otherwise you should configure the server to allow requests from localhost:8080
Configure Web Origins properly in the Keycloak notas-front client config.

Getting 401 unauthorized for Laravel sanctum

I am using Laravel Sanctum with Vuejs SPA. Both reside on same top level domain
Laravel backend : app.demo.localhost
Vue SPA : app-spa.demo.localhost
Login and logout (endpoints) are working correctly when called from VueJS SPA using axios and XSRF-TOKEN is succesfully set, but when I call other api end points it gives me 401 unauthorized.
In axios this is being set
axios.defaults.withCredentials = true;
I have the below configurations
In Laravel .env
SESSION_DRIVER=cookie
SESSION_DOMAIN=.demo.localhost
SANCTUM_STATEFUL_DOMAINS=app-spa.demo.localhost
In Routes/Api.php
Route::middleware('auth:sanctum')->get('api/user', function (Request $request) {
return $request->user();
});
In cors.php
'paths' => ['api/*', 'sanctum/csrf-cookie', 'login', 'logout'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
Could someone help me out please?
If you are using php artisan serve add the port number to SANCTUM_STATEFUL_DOMAINS. So if your port number is 8000:
SESSION_DRIVER=cookie
SESSION_DOMAIN=.demo.localhost
SANCTUM_STATEFUL_DOMAINS=app-spa.demo.localhost:8000
Your SANCTUM_STATEFUL_DOMAINS must match the url in your browser. The port number should not be on the SESSION_DOMAIN.
Following are the 8 steps that I follow while setting up Laravel sanctum check if you missed anything
Step1 composer require laravel/sanctum
Step2 php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider
Step3 php artisan migrate (you can ignore this if you're using spa)
Step4 uncomment this line from app/http/kernel.php \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
Step5 In config/cors.php update 'supports_credentials' => true,
Step6 In .env file update SESSION_DRIVER=cookie & add new line of SESSION_DOMAIN=localhost (even if your using any port like 8080 just mention localhost in session_domain)
Step7 In config/sanctum.php add your client domain along with port(if local) in stateful as follows, in my case for vue CLI it's usually localhost:8080 & for nuxt its localhost:3000 , code is as follows
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:8000,localhost:8080,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),
Mostly if your stateful (step7) is not setup properly you will get 401 unauthorized or it will try to redirect you to the home page along with cors policy error
Step8 Do not forget to await until sanctum/csrf-cookie promise is resolved
async login() {
await axios.get("http://localhost:8000/sanctum/csrf-cookie");
await axios.post("http://localhost:8000/login", {
email: "kunal#gmail.com",
password: "password",
});
let response = await axios.get("http://localhost:8000/api/user");
console.log(response.data);
},
For anyone dealing with localhost:
SESSION_DRIVER=cookie
SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost:8080(port number you use)
I just encountered the same problem. I configured all the options according to the official documentation, but I couldn't get the authorization.
Then I use routes/web.php instead of routes/api.php, so I can use sanctum middleware very well.
Now the problem seems obvious,Axios withCredentials maybe need to place in the correct way.
const http = axios.create({
baseURL: API_URL,
withCredentials: true
})
maybe not work. So I add {withCredentials: true} like
http.get('/api/whoami', {withCredentials: true})
.then(res => {
console.log(res.data)
})
Then it works.
But the very strange thing is that it is normal now, no matter whether I clear the browser cache, cookies or Laravel's various caches, there is no previous situation
For me i just had to place the host with port number:
SANCTUM_STATEFUL_DOMAINS=127.0.0.1:5173
and it started working.
Maybe this helps someone.
My problema was.... (no read with attention)
If your SPA needs to authenticate with private / presence broadcast channels, you should place the Broadcast::routes method call within your routes/api.php file:
Hi i found a solution.
My SPA is Vue v3 working on 3000 port.
Also my backend is working on 80 port. (laravel 8.1)
Make Stateful Domains in config/sanctum.php like that
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost:3000',
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),
Adding only one and correct domain on their, worked for me magically. I wrote before there whole possible variant of ports, it made me crazy and cost a couple days and nights.
My issue was I setup the domain in the wrong place.
I thought was an array of domains, in config/sanctum.php, but not, needs to be placed within the string:
OK:
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1,myownlocaldomain.test,myownlocaldomain.test:8080', <-------- OK
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),
BAD:
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : '',
'myownlocaldomain.test', <----- BAD
'myownlocaldomain.test:8080', <---- BAD
))),
I hope I save days of work to someone else...

Set cookies for cross origin requests

How to share cookies cross origin? More specifically, how to use the Set-Cookie header in combination with the header Access-Control-Allow-Origin?
Here's an explanation of my situation:
I am attempting to set a cookie for an API that is running on localhost:4000 in a web app that is hosted on localhost:3000.
It seems I'm receiving the right response headers in the browser, but unfortunately they have no effect. These are the response headers:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:3000
Vary: Origin, Accept-Encoding
Set-Cookie: token=0d522ba17e130d6d19eb9c25b7ac58387b798639f81ffe75bd449afbc3cc715d6b038e426adeac3316f0511dc7fae3f7; Max-Age=86400; Domain=localhost:4000; Path=/; Expires=Tue, 19 Sep 2017 21:11:36 GMT; HttpOnly
Content-Type: application/json; charset=utf-8
Content-Length: 180
ETag: W/"b4-VNrmF4xNeHGeLrGehNZTQNwAaUQ"
Date: Mon, 18 Sep 2017 21:11:36 GMT
Connection: keep-alive
Furthermore, I can see the cookie under Response Cookies when I inspect the traffic using the Network tab of Chrome's developer tools. Yet, I can't see a cookie being set in in the Application tab under Storage/Cookies. I don't see any CORS errors, so I assume I'm missing something else.
Any suggestions?
Update I:
I'm using the request module in a React-Redux app to issue a request to a /signin endpoint on the server. For the server I use express.
Express server:
res.cookie('token', 'xxx-xxx-xxx', { maxAge: 86400000, httpOnly: true, domain: 'localhost:3000' })
Request in browser:
request.post({ uri: '/signin', json: { userName: 'userOne', password: '123456'}}, (err, response, body) => {
// doing stuff
})
Update II:
I am setting request and response headers now like crazy now, making sure that they are present in both the request and the response. Below is a screenshot. Notice the headers Access-Control-Allow-Credentials, Access-Control-Allow-Headers, Access-Control-Allow-Methods and Access-Control-Allow-Origin. Looking at the issue I found at Axios's github, I'm under the impression that all required headers are now set. Yet, there's still no luck...
Cross site approach
To allow receiving & sending cookies by a CORS request successfully, do the following.
Back-end (server) HTTP header settings:
Set the HTTP header Access-Control-Allow-Credentials value to true.
Make sure the HTTP headers Access-Control-Allow-Origin and Access-Control-Allow-Headers are set. Don't use a wildcard *. When you set the allowed origin make sure to use the entire origin including the scheme, i.e. http is not same as https in CORS.
For more info on setting CORS in express js read the docs here.
Cookie settings:
Cookie settings per Chrome and Firefox update in 2021:
SameSite=None
Secure
When doing SameSite=None, setting Secure is a requirement. See docs on SameSite and on requirement of Secure. Also note that Chrome devtools now have improved filtering and highlighting of problems with cookies in the Network tab and Application tab.
Front-end (client): Set the XMLHttpRequest.withCredentials flag to true, this can be achieved in different ways depending on the request-response library used:
ES6 fetch() This is the preferred method for HTTP. Use credentials: 'include'.
jQuery 1.5.1 Mentioned for legacy purposes. Use xhrFields: { withCredentials: true }.
axios As an example of a popular NPM library. Use withCredentials: true.
Proxy approach
Avoid having to do cross site (CORS) stuff altogether. You can achieve this with a proxy. Simply send all traffic to the same top level domain name and route using DNS (subdomain) and/or load balancing. With Nginx this is relatively little effort.
This approach is a perfect marriage with JAMStack. JAMStack dictates API and Webapp code to be completely decoupled by design. More and more users block 3rd party cookies. If API and Webapp can easily be served on the same host, the 3rd party problem (cross site / CORS) dissolves. Read about JAMStack here or here.
Sidenote
It turned out that Chrome won't set the cookie if the domain contains a port. Setting it for localhost (without port) is not a problem. Many thanks to Erwin for this tip!
Note for Chrome Browser released in 2020.
A future release of Chrome will only deliver cookies with cross-site
requests if they are set with SameSite=None and Secure.
So if your backend server does not set SameSite=None, Chrome will use SameSite=Lax by default and will not use this cookie with { withCredentials: true } requests.
More info https://www.chromium.org/updates/same-site.
Firefox and Edge developers also want to release this feature in the future.
Spec found here: https://datatracker.ietf.org/doc/html/draft-west-cookie-incrementalism-01#page-8
In order for the client to be able to read cookies from cross-origin requests, you need to have:
All responses from the server need to have the following in their header:
Access-Control-Allow-Credentials: true
The client needs to send all requests with withCredentials: true option
In my implementation with Angular 7 and Spring Boot, I achieved that with the following:
Server-side:
#CrossOrigin(origins = "http://my-cross-origin-url.com", allowCredentials = "true")
#Controller
#RequestMapping(path = "/something")
public class SomethingController {
...
}
The origins = "http://my-cross-origin-url.com" part will add Access-Control-Allow-Origin: http://my-cross-origin-url.com to every server's response header
The allowCredentials = "true" part will add Access-Control-Allow-Credentials: true to every server's response header, which is what we need in order for the client to read the cookies
Client-side:
import { HttpInterceptor, HttpXsrfTokenExtractor, HttpRequest, HttpHandler, HttpEvent } from "#angular/common/http";
import { Injectable } from "#angular/core";
import { Observable } from 'rxjs';
#Injectable()
export class CustomHttpInterceptor implements HttpInterceptor {
constructor(private tokenExtractor: HttpXsrfTokenExtractor) {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// send request with credential options in order to be able to read cross-origin cookies
req = req.clone({ withCredentials: true });
// return XSRF-TOKEN in each request's header (anti-CSRF security)
const headerName = 'X-XSRF-TOKEN';
let token = this.tokenExtractor.getToken() as string;
if (token !== null && !req.headers.has(headerName)) {
req = req.clone({ headers: req.headers.set(headerName, token) });
}
return next.handle(req);
}
}
With this class you actually inject additional stuff to all your request.
The first part req = req.clone({ withCredentials: true });, is what you need in order to send each request with withCredentials: true option. This practically means that an OPTION request will be send first, so that you get your cookies and the authorization token among them, before sending the actual POST/PUT/DELETE requests, which need this token attached to them (in the header), in order for the server to verify and execute the request.
The second part is the one that specifically handles an anti-CSRF token for all requests. Reads it from the cookie when needed and writes it in the header of every request.
The desired result is something like this:
For express, upgrade your express library to 4.17.1 which is the latest stable version. Then;
In CorsOption: Set origin to your localhost url or your frontend production url and credentials to true
e.g
const corsOptions = {
origin: config.get("origin"),
credentials: true,
};
I set my origin dynamically using config npm module.
Then , in res.cookie:
For localhost: you do not need to set sameSite and secure option at all, you can set httpOnly to true for http cookie to prevent XSS attack and other useful options depending on your use case.
For production environment, you need to set sameSite to none for cross-origin request and secure to true. Remember sameSite works with express latest version only as at now and latest chrome version only set cookie over https, thus the need for secure option.
Here is how I made mine dynamic
res
.cookie("access_token", token, {
httpOnly: true,
sameSite: app.get("env") === "development" ? true : "none",
secure: app.get("env") === "development" ? false : true,
})
Pim's answer is very helpful. In my case, I have to use
Expires / Max-Age: "Session"
If it is a dateTime, even it is not expired, it still won't send the cookie to the backend:
Expires / Max-Age: "Thu, 21 May 2020 09:00:34 GMT"
Hope it is helpful for future people who may meet same issue.
In the latest chrome standard, if CORS requests to bring cookies, it must turn on samesite = none and secure, and the back-end domain name must turn on HTTPS,
frontend
`await axios.post(`your api`, data,{
withCredentials:true,
})
await axios.get(`your api`,{
withCredentials:true,
});`
backend
var corsOptions = {
origin: 'http://localhost:3000', //frontend url
credentials: true}
app.use(cors(corsOptions));
const token=jwt.sign({_id:user_id},process.env.JWT_SECRET,{expiresIn:"7d"});
res.cookie("token",token,{httpOnly:true});
hope it will work.
After more then a day of trying all your suggestions and many more, I surrender.
Chrome just does not accept my cross domain cookies on localhost.
No errors, just silently ignored.
I want to have http only cookies to safer store a token.
So for localhost a proxy sounds like the best way around this. I haven't really tried that.
What I ended up doing, maybe it helps someone.
Backend (node/express/typescript)
set cookie as you normally would
res.status(200).cookie("token", token, cookieOptions)
make a work around for localhost
// if origin localhost
response.setHeader("X-Set-Cookie", response.getHeader("set-cookie") ?? "");
Allow x-set-cookie header in cors
app.use(cors({
//...
exposedHeaders: [
"X-Set-Cookie",
//...
]
}));
Frontend (Axios)
On the Axios response
remove the domain= so it's defaulted.
split multiple cookies and store them locally.
// Localhost cookie work around
const xcookies = response.headers?.["x-set-cookie"];
if(xcookies !== undefined){
xcookies
.replace(/\s+Domain=[^=\s;]+;/g, "")
.split(/,\s+(?=[^=\s]+=[^=\s]+)/)
.forEach((cookie:string) => {
document.cookie = cookie.trim();
});
}
Not ideal, but I can move on with my life again.
In general this is just been made to complicated I think :-(
Update my use case maybe we can resolve it?
It's a heroku server with a custom domain.
According to this article that should be okay
https://devcenter.heroku.com/articles/cookies-and-herokuapp-com
I made an isolated test case but still no joy.
I'm pretty sure I've seen it work in FireFox before but currently nothing seems to work, besides my nasty work around.
Server Side
app.set("trust proxy", 1);
app.get("/cors-cookie", (request: Request, response: Response) => {
// http://localhost:3000
console.log("origin", request.headers?.["origin"]);
const headers = response.getHeaders();
Object.keys(headers).forEach(x => {
response.removeHeader(x);
console.log("remove header ", x, headers[x]);
});
console.log("headers", response.getHeaders());
const expiryOffset = 1*24*60*60*1000; // +1 day
const cookieOptions:CookieOptions = {
path: "/",
httpOnly: true,
sameSite: "none",
secure: true,
domain: "api.xxxx.nl",
expires: new Date(Date.now() + expiryOffset)
}
return response
.status(200)
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Allow-Origin", "http://localhost:3000")
.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT")
.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
.cookie("test-1", "_1_", cookieOptions)
.cookie("test-2", "_2_", {...cookieOptions, ...{ httpOnly: false }})
.cookie("test-3", "_3_", {...cookieOptions, ...{ domain: undefined }})
.cookie("test-4", "_4_", {...cookieOptions, ...{ domain: undefined, httpOnly: false }})
.cookie("test-5", "_5_", {...cookieOptions, ...{ domain: undefined, sameSite: "lax" }})
.cookie("test-6", "_6_", {...cookieOptions, ...{ domain: undefined, httpOnly: false, sameSite: "lax" }})
.cookie("test-7", "_7_", {...cookieOptions, ...{ domain: "localhost"}}) // Invalid domain
.cookie("test-8", "_8_", {...cookieOptions, ...{ domain: ".localhost"}}) // Invalid domain
.cookie("test-9", "_9_", {...cookieOptions, ...{ domain: "http://localhost:3000"}}) // Invalid domain
.json({
message: "cookie"
});
});
Client side
const response = await axios("https://api.xxxx.nl/cors-cookie", {
method: "get",
withCredentials: true,
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
}
});
Which yields the following reponse
I see the cookies in the Network > request > cookies Tab.
But no cookies under Application > Storage > Cookies nor in document.cookie.
Pim's Answer is very helpful,
But here is an edge case I had gone through,
In my case even though I had set the Access-Control-Allow-Origin to specific origins in BE , In FE I received it as * ; which was not allowed
The problem was, some other person handled the webserver setup,
in that, there was a config to set the Access-Control-* headers which was overriding my headers set from BE application
phew.. took a while to figure it out .
So, if there is mismatches in what you set and what you received, Check your web server configs also.
Hope this would help
for me regarding the sameSite property, after enabling CORS I also add "CookieSameSite = SameSiteMode.None"
to the CookieAuthenticationOptions in the Startup file
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
.....
CookieSameSite = SameSiteMode.None,
.....
}
This is an answer to "Lode Michels" from above regarding CORS cookie with the Heroku server, (and for other cloud providers, like AWS)
The reason your CORS cookie can't be set is because Heroku strip down SSL certificate at Load Balancer, so when you try to set the "secure" cookie at the server, it fails since it's no longer from the secure connection.
You can explicitally specify if the connection is secure, rather than the cookie module examining request.
https://github.com/pillarjs/cookies
with koa, add this:
ctx.cookies.secure = true;
edit: I can't comment on that answer directly due to lower than 50 reputation
This code worked for me
In the backend
Set credentials to true in your corsOptions:
const corsOptions = {
credentials: true,
};
Set cookies before sending requests:
res.cookie('token', 'xxx-xxx-xxx', {
maxAge: 24*60*60*1000, httpOnly: true,
SameSite:"None" })
In the frontend
Request in browser (using axios):
axios.post('uri/signin',
JSON.stringify({ username: 'userOne',
password: '123456'}),.
{withCredentials:true})
.the(result
=>console.log(result?.data))
.catch(err => console.log(err))