We have an AWS Lambda API server that is placed behind an APIGateway endpoint, and a React.js client that lives in an S3 bucket and served through Cloudfront.
When the user logs in the API server sends a cookie in the Set-Cookie header, but the browser doesn't send it back in subsequent requests. We've tried it on Chrome 90 and the latest Firefox, but no dice.
After log-in, the React code does a fetch like this:
fetch(`${url}/api/<blahblah>`, {
method: 'GET',
credentials: 'include',
headers: new Headers({
accept: 'application/json'
})
But the browser appears to decide that the cookie doesn't match and so doesn't send it in the request.
I have tried all manner of flags in the Set-Cookie, and the browsers are happy to store it with the initial response.
Currently the cookie looks like this:
<cookie contents>; Expires=Fri, 21 May 2021 12:00:32 GMT; Max-Age=86400; HttpOnly; Path=/; SameSite=Lax
Although I have tried setting the domain explicitly, setting the Secure flag with SameSite=None, removing the HttpOnly flag, and probably a dozen other combinations. The browsers all say that the cookie is valid, with no warnings or anything. Both the frontend and backend are using HTTPS, so Secure; SameSite=None should work, right?
The response headers from the server include access-control-allow-credentials: true, and access-control-allow-origin is set to the right Cloudfront URL.
I have had it working once on a localhost to localhost request, but even that doesn't seem to work any more.
What have I missed? Is it an AWS setting that needs changing? Is it the fetch call that is missing an option?
Related
Bellow code references and request references have comments these were added in SO to explain my understanding original requests and code contain no comments.
I am aware of the standard of using auth headers for fetch requests. what I need to do is get the cookie that server A sets to server B without having to pass it via javascript.
I have Server A: http://127.0.0.1:8080
contains index.html
index.html when cookie jar is looked at contains a cookie
I also have Server B: http://0.0.0.0:8081. <- duno if relevant port and ip are different
http://127.0.0.1:8080/index.html makes the bellow request
let url = "http://0.0.0.0:8081/write" //this url is o a different server so certain headers are needed
let cookies = document.cookie
console.log(cookies) //this logs the cookie so I know its defo there
let otherPram= {
credentials: 'include', //this is what I need to tell the browser to include cookies
method: "GET"
};
fetch(url, otherPram)
After the request is made the browser makes an options call to http://0.0.0.0:8081/write with response:
access-control-allow-credentials: true
access-control-allow-headers: accept, authorization, content-type, origin, x-requested-with, access-control-allow-credentials, cookie, access-control-allow-origin
access-control-allow-methods: GET, POST, OPTIONS
access-control-allow-origin: http://127.0.0.1. //also tried this with http://127.0.0.1:8080
access-control-expose-headers: Cache-Control, Content-Language, Content-Type, cookie
access-control-max-age: 600
connection: keep-alive
content-length: 0
date: Thu, 16 Jan 2020 08:22:19 GMT
however the request contains no cookies.
to the best of my knowledge it should send the cookies with the fetch request.
Cookies belong to an origin.
let cookies = document.cookie
console.log(cookies) //this logs the cookie so I know its defo there
That shows that there are cookies for the origin of the HTML document.
After the request is made the browser makes an options call to http://0.0.0.0:8081/write
So you are making a cross-origin request.
The cookies do not belong to that origin so the browser will not send them.
If you want to send cookies to http://0.0.0.0:8081/, then you need to make a request to http://0.0.0.0:8081/ and have it use a Set-Cookie header in the response to set them in the first place. The browser won't set the cookies from :8080 to :8081 because they aren't :8081's cookies.
Typically web services will use an Authorization header instead of cookies.
let otherPram= {
headers: {
"Authorization": "Bearer SomeToken"
},
credentials: 'include', //this is what I need to tell the browser to include cookies
method: "GET"
};
Aside: I removed "content-type": "application/json". You are making a GET request so the request has no content to specify the type of.
Experimenting on the server at least with sub domains you can share cookies which is enough in this case.
Along with all the cors properties and the fetch include. The cookie being set needs the domain to be set too.
Set-Cookie: myCookie=value; domain=root.com
All subdomains of root.com will share that specific cookie.
When I send a response from my server after authentication, I'm setting an authentication token cookie in the client's browser using this header:
Set-Cookie:mysite_auth=encodedJwtHere.JustPretend; SameSite=lax; domain=subdomain.mydomain.com; HTTPOnly; Max-Age=600; Secure; path=/
However, when I open EditThisCookie in Chrome, I can see that the domain is being set to .subdomain.mydomain.com automatically.
From what I thought I understood, this shouldn't be an issue. When I request https://subdomain.mydomain.com in the browser, the cookie is being sent.
My issue happens when I try to make a CORS request. I'm developing a javascript app and serving it on localhost. When I make an AJAX call to https://subdomain.mydomain.com, the cookie is not sent.
I have all of the proper headers set on the response:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type, *
Access-Control-Allow-Origin:*
I have the {withCredentials:true} config on my request.
If I open https://subdomain.mydomain.com in the browser, then with EditThisCookie, I remove the prefix dot, I.E. I change .subdomain.mydomain.com to subdomain.mydomain.com, suddenly my AJAX calls from localhost work. The cookie is sent with the request.
So my question is, first of all, why is the cookie not being sent when there is a prefix dot, and is there a way to resolve this issue without manually editing the domain every time my cookie is refreshed?
If you're sending credentials, you can't respond with Access-Control-Allow-Origin:* - you must respond with a value that EXACTLY mirrors the Origin request header, e.g. Access-Control-Allow-Origin: {value-of-Origin-Header}.
In your case, that would presumably be Access-Control-Allow-Origin: https://subdomain.mydomain.com. Best not to hard-code it though - just mirror back Origin value.
I am having issues with trying to set a cookie from a Response Header, I can see the set-cookie key with all the options that i have specified but for some reason it is not being set in the browser (Chrome).
I am setting the cookie using koajs, and reads as follows:
this.cookies.set(’test-cookie’, ‘valid’, { domain: ‘.test.io’, httpOnly: false, maxAge: 604800000 })
this is what I get in the response:
GET https://api.test.io/conversion
set-cookie: test-cookie=valid; path=/; expires=Mon, 12 Jun 2017 14:23:40 GMT; domain=.test.io;
I have another request (GET https://identity.test.io/identity) that does a similar request and has the same set-cookie response and i can see this cookie in chrome dev tools.
The only difference is api.test.io goes through several redirects (301), however we do not think that is the issue as we still see the set-cookie key in the final response header.
nb: this cookie needs to work across multiple sites which is why we don’t set secure, signed or httpOnly.
My answer is strictly for local testing, but I am putting it here as an answer cause your question is exactly what I searched for before I fixed it.
My php.ini file had the session.auto_start setting set to 0. I set it to 1, and the browser started saving cookies that were in response header. (using WAMP with PHP 7.0.29)
the response header is
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Origin, X-Requested-With, x-request, Content-Type, Accept
Access-Control-Allow-Origin:*
Cache-Control:private
Connection:close
Content-Length:100
Content-Type:application/json; charset=utf-8
Date:Tue, 14 Feb 2017 02:45:56 GMT
Server:nginx/1.2.8
Set-Cookie:USER=6ae633831f39447688892e6b2b156cec; Max-Age=604800; Path=/
Set-Cookie:USERINFO=298967; Max-Age=604800; Path=/
X-Powered-By:node.js
X-Ua-Compatible:chrome=1
the cookie format's right (used cookie package to serialize ). the server is developed by node.js.
not only chrome, Firefox doesn't work too. the document.cookie is empty and also i can't see cookie in application section of chrome developer tool.
Any wrong in response header ?? Please help .
This problem occur due to multiple responses from server to client.
For example if you are sending a response to the server using response.send() and same time using
you are using response.setHeader()
This problem can be solve by creating cookie in client side using javascript.
And reading its value from node.js
The answer is because i used fetch() API that have to pass {credentials => 'same-origin'} option.
Exactly what the title suggests:
I perform an ajax request to my server, it responds with a 403 but there are headers I want to retrieve and save on localStorage. This is for a phonegap app (Android and iOS), so the initiating domain isLocal (file://). When performing the call, I use the following code to try to intercept the response, but it returns undefined or an empty string.
Ajax:
$.ajax({
url: serverLink+action,
type: "POST",
data: "access_token="+accessToken+"&uid="+uid,
crossDomain: true,
complete: function(resp){
var header = resp.getAllResponseHeaders();
var match = header.match(/(Set-Cookie|set-cookie): (.+?);/);
if (match) session = match[2];
console.log(header, session)
}
})
Response Headers
Connection Keep-Alive
Content-Encoding gzip
Content-Length 1198
Content-Type text/html
Date Fri, 13 Apr 2012 22:51:02 GMT
Keep-Alive timeout=15, max=100
Server Apache/2.2.14 (Ubuntu)
Set-Cookie sessionid=ebd26167e32bada2d2ed0bd3cc16d8a2; expires=Fri, 27-Apr-2012 22:51:02 GMT; Max-Age=1209600; Path=/
Vary Cookie,Accept-Encoding
Further reading led me to here, which speaks of the CSRF on a django server. We are using a django server and either this or the 403 is the problem I suspect. There doesn't seem to be a way (from the example answer there) to collect the cookie from webview and send it back to the server on subsequent requests.
use the jquery XHR object which as a method getAllResponseHeaders() which should provide what you are after.
http://api.jquery.com/jQuery.ajax/
This problem was most definitely caused by CSRF protection on the django server. Disabling or implementing workarounds as per django is the only way around this.
Actually this post helped tremendously: Django CSRF check failing with an Ajax POST request