fetch() cannot set cookies received from the server? fetch() cannot set cookies received from the server? express express

fetch() cannot set cookies received from the server?


I have found the solution. The core of this problem being that my button to trigger the fetch is on http://localhost:3000/. The server is on http://localhost:5555/ (I am simulating real environment on my own machine)

The problem is that this fetch call

  async trySetCookie()  {    await fetch("http://localhost:5555/s",{       method: 'GET',       credentials: 'same-origin'    })  }

Without credentials, the browser cannot send or receive cookies via fetch (https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials)

With credentials as same-origin I can see the cookies coming from the server in the Set-Cookie response header, but nothing is being stored in the browser. One strange thing is that this response always have HttpOnly tagged after the cookie string regardless of my {httpOnly : true/false} settings on the server. In the case of manually using the browser to the page to do GET request, HttpOnly is being respected as usual, and the cookies are set.

So the solution is to set credentials as include to allow cross-origin cookie sending.

  async trySetCookie()  {    await fetch("http://localhost:5555/s",{       method: 'GET',       credentials: 'include'    })  }

Also, on the server side you need to allow a particular origin manually with new headers:

app.get("/s", (req,res) => {    res.cookie("bsaSession", req.session.id, {httpOnly:false})    res.header('Access-Control-Allow-Origin', 'http://localhost:3000')    res.header('Access-Control-Allow-Credentials','true'    res.send("set")})

Not doing this results in

XMLHttpRequest cannot load http://localhost:5555/s. Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.

But the cookie will be set regardless of this error. Still nice to include that header to silence the error.

If you are using cors middleware for Express it is even easier. You can just use these options

var corsOptions = {  origin: 'http://localhost:3000',  credentials:  true}app.use(cors(corsOptions))

And of course credentials: 'include' is still required at the client side.


5argon's solution was great for me otherwise, but I had to set origin in express cors to true. So in backend:

app.use(  cors({    origin: true,    credentials: true,  }));

And in fetch:

fetch("http://localhost:5555/s", {    method: 'GET',    credentials: 'include'})