Cookie is not being set - Nodejs and express - cookies

I'm trying to set a cookie on the browser via httponly but is not being set. I deployed the server and the client on different hosts, and I think is maybe that but I can't find a solution.
That's how I configure the cookie object when it comes to sending the cookie to the browser:
res.cookie('refreshtoken', token, {
httpOnly: true,
secure: true,
sameSite: "none"
})
How can I solve this problem?

Related

Secure Cookies not working with hostname set in hosts file

I have cookies set as secure, but it's working as localhost. But with the domain name set in the hosts file, chrome is not sending the cookies to server resulted in request failing.
i am running my server on the localhost with the following cookie set, the cookie is being sent by chrome to my server.
cookie := http.Cookie{Name: "XSRF-TOKEN", Value: csrf.Token(r), Expires: expiration, Path: "/", HttpOnly: false, Secure: true}
I have set the following in my host file and trying to open from chrome x.test.in the cookie is not getting passed . chrome reporting as set-cookie was blocked because it has the secure attribute but was not received the following code is in golang and using gorilla mux
127.0.0.1 x.test.in
Did you call the server with HTTP or HTTPS? If the "Secure" Flag is set on the cookie it can only be set after an HTTPS call
If it was indeed blocked by Chrome you can still see it by going into the "Network" Tab of your developer tools, select the request, click on "Cookies" and select "show filtered out request cookies". The blocked cookie should appear and you should see there why this was the case.
You can try this in an other browser. I think chrome means, the cookie is a fake-secure cookie.

Why am I getting "Indicate whether to send a cookie in a cross-site request by specifying its SameSite attribute"?

In a Chrome warning, it says:
Specify SameSite=None and Secure if the cookie should be sent in cross-site requests. This enables third-party use.
How do I do this correctly using express-session?
app.use(
cors({
credentials: true,
origin: ["http://localhost:3000", "https://elated-jackson-28b73e.netlify.app"] //Swap this with the client url
})
);
var sess = {
secret: 'keyboard cat',
cookie: {}
}
if (app.get('env') === 'production') {
app.set('trust proxy', 1) // trust first proxy
sess.cookie.secure = true // serve secure cookies
sess.cookie.sameSite = 'none'
}
app.use(session(sess))
you are getting this because you are using a resource from another site and that server is attempting to set a "cookie" but, it does not have the SameSite attribute set, which is being reported in newer versions of browsers.
this (may) also be shown if you are trying to access the server page from local computer (xampp), which generally doesn't has SSL installed;
set the header line in your server page (if in PHP) as below:
header("Set-Cookie: cross-site-cookie=whatever; SameSite=None; Secure");
(remember: this must be solved from the server side.)
i got the same issue when run my code in localhost. The affected resource is _ga, _gid, _utma, _utmz. All of them from unpkg.com
and i got marker image leaflet failed request but doesnt affect the page.
since i dont understand what the specific problem so i just delete the affected resource cookies in inspect element and the code will run without notif again.
thought i know if it's better to not answer based by personal experience. just tell me if it's not help at all.
If you are using Google login button or any other identity service add this:
<GoogleLogin onSuccess={() =>()} onError={() => ()} cookiePolicy='single-host-origin'/>

Cookie not being set on angular client

I have a backend app in django python and it is being served on http://localhost:8000.
I have a angular frontend which is being served on http://localhost:4200.
I have disabled CORS on django.
On hitting the login api on http://localhost:8000/auth/login/, I am getting a valid response
along with the Set-Cookie header.
Here is my angular code to print the cookies:
this.http.post<any>('http://localhost:8000/auth/login/', this.LoginForm, { observe: 'response' }).subscribe(response => {
console.log("response is ", response);
var cookies = this.cookieService.getAll();//('cookies');
console.log("cookies is :", cookies);
It prints an empty object on console.
How do I make this work? I want to use cookies for authentication.
You are trying to set cross domain cookies, which will not work straight away. There are a few steps to follow to be able to do that.
Set withCredentials: true when making the authentication request from angular
this.http.post<any>('http://localhost:8000/auth/login/', this.LoginForm, { observe: 'response', withCredentials: true })
Configure your server to return the following CORS headers: Access-Control-Allow-Credentials: true and Access-Control-Allow-Origin: http://localhost:4200
Note
One of the cookies that you are setting is HttpOnly. As such, you cannot access it from Javascript (see documentation).
You may not need to access the cookies with JS anyway. If you just want to send the cookies in the next API requests, just pass withCredentials: true to HttpClient other api calls
this.http.get('http://localhost:8000/path/to/get/resource',
{ withCredentials: true }).subscribe(response => {
Set-Cookies:
In the example in the Question, both client and server are in the same domain, localhost.
On deployment, this may not be the case.
Let us assume the domains as below,
Client : client1.client.com
Server: server1.server.com
A http request from the Angular web app in client1.client.com to https://server1.server.com/api/v1/getSomething has Set-Cookie: JSESSIONID=xyz in the response header.
The cookie will be set on server1.server.com and NOT on client1.client.com.
You can enter server1.server.com in the URL bar and see the cookie being set.
withCredentials:
There is no need for the angular app to read the cookie and send it in the following requests. withCredentials property of http request can be used for this.
Refer: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
Example:
public getSomething(): Observable<object> {
const httpOptions = {
withCredentials: true
};
return this.http.get(`${this.serverUrl}/getSomething`, httpOptions);
}
Refer: https://angular.io/api/common/http/HttpRequest
withCredentials will set the cookies from the server's domain in the requests to the server.
As mentioned before Set-Cookie: JSESSIONID=xyz in the response from server1.server.com will be set in server1.server.com. The Angular app in client1.client.com need not read it. withCredentials will take care of it.
cross domain issues:
When the server and client are in different domains, using withCredentials may not work in all browsers, as they are considered as third party cookies.
In my recent testing on May 2020, I found that withCredentials is not working in certain browsers when the client and server are in different domains.
In Safari, the issue occurs when "Prevent cross-site tracking" is enabled (by default). The issue is prevented by disabling the same. https://support.apple.com/en-in/guide/safari/sfri40732/mac
In Android apps, the issue can be avoided by using Chrome Custom Tabs instead of Android WebView. https://github.com/NewtonJoshua/custom-tabs-client , https://developer.chrome.com/multidevice/android/customtabs
Same domain:
Looks like mainstream browsers are moving to block third-party cookies.
Safari - Full Third-Party Cookie Blocking and More
Chrome (by 2022) - Building a more private web: A path towards making third party cookies obsolete
The solution is to have both the client and server in the same domain.
Client: client1.myapp.com
Server: server1.myapp.com
And in the Set-Cookie response include the root domain too.
Example: "JSESSIONID=xyz; Domain=.myapp.com; Path=/"
This will make sure the cookies are set in all cases.

I can't set cookie on localhost

I'm using NodeJS with the Express framework with the cookie-parser middleware on localhost:3333. My frontend is served by react dev server on localhost:3000. This is my first attempt at anything to do with cookies. Here are the options i set for my cookie: { expires: maxAge , httpOnly: true, sameSite: 'none', secure: true, domain: null }. I've also tried with and without the sameSite, httpOnly and secure options. As well as domain=localhost.
Here is a header from the http response i get when trying to set a cookie:
Set-Cookie:
sessionid=119faa6a3fcfab0628998ff2592e04ceb06cda12; Path=/; Expires=Sun, 29 Jan 2023 15:20:16 GMT; HttpOnly; Secure; SameSite=None
But the problem is the cookie does NOT show up in Application/Cookies in Chrome or Storage/Cookies in Firefox. I also can't access the cookie as a request cookie on different endpoints. It does however work on my vps. The vps uses a proper domain name as well as a proxy so that all requests appear to come from the same domain/port, i don't know if that makes a difference or not.
I've also tried adding 127.0.0.1 dev.mylocalhost.com to /etc/hosts in order to fake a domain name on localhost. Just read something about this, not quite sure how that is supposed to work. I don't own this domain, this is just in my local /etc/hosts file. I have not tried using a proxy on localhost, so the cookie is being set from the server on port 3333 while the client is on port 3000. Again not sure if that makes a difference.
If you are using axios, put this when creating the instance:
const instance = axios.create({withCredentials: true, baseURL: API_URL});

Domain Wide Cookies

I have a.example.com and it sets a cookie for .example.com. Later on a.example.com sends an ajax request to b.example.com. I expect the.example.com cookie to be sent to b.example.com. But it is not.
I made sure the cookie was set on the right domain, but it does not seem to send the cookie in the ajax request for some reason.
# server A
res.cookie('images', tokens.images, { expires: config.pageExpiration(), secure: secure, domain: domain })
# server B
req.cookies.image
This makes sense, as you wouldn't expect *.com cookies to be mixed.
I suggest you pass your cookies through a server request if you really need to.