Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
905 views
in Technique[技术] by (71.8m points)

node.js - Why Chrome can’t set cookie

I have a response from my server. Response Headers contains a valid Set-Cookie. Chrome Response/Cookies says that I have 1 cookie, ok. But... The cookie is not setting into DevTools/Application/Cookies

/*
 My frontend on Vue
 I renamed 127.0.0.1 to www.example.com
 So running on www.example.com:80 or just www.example.com
*/
let response = await axios({
               method: 'post',
               url: 'http://127.0.0.1:3000/api/login', // my Node server on 3000 port   
               data: {
                   email : login,
                   password: password,
               },
            })
/*
 My backend part on Node.js+Express
 Running on localhost:3000 or 127.0.0.1:3000
 CookieParser() is setted
*/
let options = {
              maxAge: 345600000,
              httpOnly: true,
              path: '/',
            }

res
   .cookie('test', 'test', options)
   .cookie('access_token', token, options) //token contains a JWT string
   .send('');
/*
 Chrome Response Headers
*/
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Sun, 09 Feb 2020 08:52:22 GMT
ETag: W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"
Set-Cookie: test=test; Max-Age=345600; Path=/; Expires=Thu, 13 Feb 2020 08:52:22 GMT; HttpOnly
Set-Cookie: access_token=example; Max-Age=345600; Path=/; Expires=Thu, 13 Feb 2020 08:52:22 GMT; HttpOnly
X-Powered-By: Express
/*
 Chrome request headers
*/
Accept: application/json, text/plain, '*/*'
Accept-Encoding: gzip, deflate, br
Accept-Language: ru-RU,ru;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 45
Content-Type: application/json;charset=UTF-8
Host: 127.0.0.1:3000
Origin: http://www.example.com
Pragma: no-cache
Referer: http://www.example.com/
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36

Moreover I tried to use Microsoft Edge, but the problem isn't gone. Why browsers can't set-cookie considering they know about receiving Cookies?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you want to do some background reading then I suggest you look for guides to CORS (cross-origin resource sharing) and, specifically, how to set cookies when using CORS.

Using your original code you'll need to change it to set withCredentials to true:

let response = await axios({
    method: 'post',
    url: 'http://127.0.0.1:3000/api/login', // my Node server on 3000 port   
    data: {
        email : login,
        password: password,
    },
    withCredentials: true
})

Behind the scenes this will set the withCredentials flag on XMLHttpRequest:

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials

You'll then get CORS errors in your console. If you work your way through those errors you should be able to get it working. These errors will include...

Firstly, the server will need to return the header Access-Control-Allow-Credentials: true. This also applies to the preflight OPTIONS request.

Secondly, you're currently using Access-Control-Allow-Origin: * but that isn't allowed for requests using credentials. That'll need to be Access-Control-Allow-Origin: http://www.example.com. Likewise for the preflight.

At that point the cookie should be set in most browsers (more on browser quirks later).

To get the cookies added to subsequent requests you'll also need to set withCredentials: true on those requests. The other header changes outlined above also need to be applied. The cookies will not be included on the preflight request, just the main request.

Seeing the cookies in the browser's developer tools is not completely straightforward. Generally the tools only show cookies set for the same origin as the current page, which doesn't include the cookies set via CORS requests. To see those cookies you'll need to open another browser tab and set the URL to something that starts with the same origin as the CORS request. Be careful though, you need to pick a URL that won't set the cookies itself, otherwise that doesn't really prove anything.

Another way to check what cookies are set is to send another request (with withCredentials) and see what cookies get sent.

Then we have the browser-specific issues...

In Safari it is really difficult to get cookies to set over CORS. If Safari is a target browser for you then I suggest doing some further research into that.

Secondly, Chrome 80 is due to change the rules around CORS cookies significantly. See:

https://www.chromium.org/updates/same-site

You'll already see warnings about this in your console with older versions of Chrome. In short, CORS cookies will need to be served over https and set the directives Secure and SameSite=None.

Update:

Since writing this answer I have created an FAQ for common CORS problems. The section explaining the use of cookies can be found at https://cors-errors.info/faq#cdc8.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...