0

I have a middle wear in my Express app that sets a cookie in the clients browser:

 res.cookie('token', '123');

Everything works perfect on a local environment with the front end calling local the server:

 axios
  .post(`http://localhost:3000/createSomething`, { 'field': "value"})
  .then(res => {
    console.log('res', res)
  })
  .catch(err => {
    return Promise.reject(
      new Error('There is an issue with the /createSomething endpoint')
    );
  });

In this situation the cookie gets set and I can see it in my dev tools under the Cookies section. The issue is when I change my front end call to point to the AWS Elastic Beanstalk environment:

http://localhost:3000/createSomething -> https://testEnvironment.com/createSomething

The call is successful but no cookie is created in the clients browser. Although, In the response headers I do see:

set-cookie: paigetoken=123; Path=/

A few further details:

  • There is a yellow warning symbol at the end of the set-cookie.
  • Using CORS
  • There is an application load balancer in the AWS environment that handles https. Could this be a factor?

How can I resolve this issue and have my Express app in AWS ELB environment successfully set a cookie in the clients browser? Any insight would be greatly appreciated!

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
emarel
  • 371
  • 7
  • 30
  • " yellow warning" - is there any message with the warning icon? – Marcin Feb 23 '21 at 03:33
  • "This Set-Cookie was blocked due to user preferences” (Chrome) – emarel Feb 23 '21 at 18:31
  • Are you sure you don't have any ad blockers or something that can block the cookie in the browser? – Marcin Feb 23 '21 at 23:13
  • I wont be able to control clients browsers and ad blockers so I'm looking for a solution that is independent of browser settings. Also to note, the issue did not arise locally. It seems to be more of a CORS / AWS issue – emarel Feb 24 '21 at 04:09

2 Answers2

2

You need to pass SameSite=None; Secure along with the set-cookie information as set-cookie: paigetoken=123; Path=/;SameSite=None; Secure

Chrome dosen't allow setting cookies from domain without using SameSite options.

https://digiday.com/media/what-is-chrome-samesite/

PS: This is ignored when request is originated from local environment. (localhost/127.0.0.1)

In NodeJs, It will work something like this.

res.cookie('token', '123', { sameSite: 'None', path: '/', secure: true })

Here's some reference :

http://expressjs.com/en/4x/api.html#res.cookie

Atul Sharma
  • 9,397
  • 10
  • 38
  • 65
  • I have come across this solution but even after setting the sameSite=none and Secure I had the same issue. – emarel Mar 03 '21 at 00:06
1

1. Change the request URL:

Since I'm not totally sure how your environment is set up, the issue may be that the client is requesting information from localhost meaning that it would be requesting data from the clients same machine. Try changing your URL in the client code to:

`${location.origin}/createSomething`

2. If that doesn't work:

This presents a security issue in most browsers. Imagine a malicious site overriding a login token cookie for lets say Google. In order for a server to set the cookie, location.origin must match in both the client and the requested endpoint.

A work around you could use is have the server send a response telling the client to set the cookie on the front-end.

For example: on the server you could do something like this to send a header with the cookie information.

res.set('X-SetCookie', JSON.stringify({ name: "token", value: "123" }));

Then in the client, something like this to actually set the cookie.

axios
  .post(`http://localhost:3000/createSomething`, { 'field': "value"})
  .then(res => {

    // Set cookie function.
    function setCookie({ name, value, expires = 1000*60*60*24*365 }) {
        const time = new Date();
        time.setTime(time.getTime() + expires);
        document.cookie = `${name}=${value};expires=${time.toUTCString()};path=/`;
    }

    // If response has the X-SetCookie header, set the cookie client side.
    if(res.headers.hasOwnProperty("X-SetCookie")) setCookie(JSON.parse(res.headers["X-SetCookie"]));
    
    console.log('res', res)
  })

Just make sure you configure CORS properly so the browser can see the header: Axios get access to response header fields

Josh Merlino
  • 622
  • 6
  • 10
  • #1 did not work for me but I have since then moved on to #2 as my solution. While this solution wont help those that are forced to have the server set the cookie, this is an excellent solution for those who are willing to have the client set the cookie. – emarel Mar 03 '21 at 00:05