Setting cookies through a CORS request - ajax

I'm porting a client-side library for an API from JSONP to CORS.
I have set all the correct headers in the server and done all the indicated things in the client, but I have a problem regarding cookies.
That API auth method works with cookies. With JSONP, it made a GET request to the API with the API key as a parameter. Then the server set a cookie at api.io.holalabs.com (API URL), so the next time it does a call to the API the server requests the cookie and make the login.
The problem is that, although I see Set-Cookie in the headers, the cookie is not set at api.io.holalabs.com so the login fails.
These are my headers:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version
Access-Control-Allow-Methods:GET
Access-Control-Allow-Origin:http://holalabs.com
Access-Control-Expose-Headers:X-Api-Version, X-Request-Id, X-Response-Time
Connection:close
Content-Length:13
Content-MD5:RjkY1fW5i5MKifxPk+r4tg==
Content-Type:application/json
Date:Fri, 13 Apr 2012 16:06:56 GMT
Server:nginx/1.0.14
Set-Cookie:apikey.sig=DYyrzLFUfJSjsmK5crkxHQg-rxQ; path=/; httponly
X-Api-Version:1.0.0
X-Request-Id:c78b4223-1caf-42db-a99e-b075bdc10ea5
X-Response-Time:2
EDIT: Using cookies in a API is a horrible idea, so now we are using a header to auth the user. Issue closed!

Issue is supposedly closed, but if anyone encounters this problem and need to use cookies, here's one possible explanation and solution:
Explanation
The session ID is sent as a cookie, and since the request is cross-domain, it's considered a third party cookie by the browser. Several browsers will block third-party cookies, and the session is lost.
Solution
Generate the session ID on the client (in the browser), use Javascript sessionStorage to store the session ID then send the session ID with each request to the server.
(Details: Javascript Cross-Domain Request With Session)

Related

Cookie not set after HTTP request with Set-Cookie response header

Context: I'm trying to couple a separate frontend (Nuxt.js) with a Laravel backend. Session (logged in user etc.) is maintained by the backend and should be stored and updated in the frontend using cookies. I am making API calls using Axios.
I am currently running my frontend on localhost:3000 and my backend on 127.0.0.1:8000. When I make API calls from the frontend, I get the following headers in the response:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://localhost:3000
Cache-Control:no-cache, private
Connection:close
Content-Type:application/json
Date:Sun, 15 Oct 2017 13:05:24 GMT
Host:127.0.0.1:8000
Set-Cookie:laravel_session=fuqQf1fX3ZwQYl7xORGPopgZhD4qw5Mfi8lFrHTJ; expires=Sun, 15-Oct-2017 15:05:24 GMT; Max-Age=7200; path=/;
Vary:Origin
X-Powered-By:PHP/7.0.10
From what I understand, the browser should now set/update the laravel_session cookie. However, when I check the cookies in Chrome devtools, nothing changes.
Are the different URLs (or at least ports) an issue here? Am I missing some kind of header or directive that is required? I've done some research but haven't found a solution yet.

Cookie in AJAX response from other domain not honored - are there workarounds

I have a server-side API on the domain api.example.com
User is visiting www.website.com where a script makes an XmlHttpRequest to api.example.com and gets a response with a cookie.
It appears the API's response cookie is not honored by the HTTP agent.
I'm aware of the non-cross-domain-leaking-cookie policy, but I thought the domain here would be api.example.com. Seems I guessed wrong.
Is there some other way that my API on api.example.com could remember user data from one site to another? If not, how could services like Criteo and other retargeting sites work, from this point of view?
Make sure your API set:
Access-Control-Allow-Credentials header to true in possible preflight response and regular response,
Access-Control-Allow-Origin header to value of the origin from the actual request,
and client sets XMLHttpRequest.withCredentials to true.

HTTP Vary: Cookie vs Cache-Control: private

I am writing a web application framework. To properly support reverse proxy servers, I want to make sure that whenever the web application is accessing cookie data, pages that are sent to the user are cached only for that user. As far as I know, there are two ways of achieving this:
header('Vary: Cookie');
or
header('Cache-Control: private');
The immediate benefit of using Vary: Cookie is that a reverse proxy server will cache non-authenticated requests. However, we're using Google Analytics which create cookies through javascript - so I am afraid the Vary: Cookie method is unusable?
For your case (using Google Analytics), this will not work as GA sets first-party cookies for ".yourdomain.tld"
As of now, I'm seeing the following first party cookies set by Google Analytics:
_gat_gtag_UA_#####_#
_ga
_gid
Cookies set by a script served by a given domain will only be sent to that domain.
The proxy will not receive the cookies set by google analytics.

how to force rack:session + sinatra to read "rack.session" from params instead of cookies

I am dealing with oauth 1.0 (twitter and flickr). Website works at port 80 and oauth server works at port 8080
Algorithm:
send ajax request to oauth server to check if user have valid access_token
open authorization window if user have no access_token or access_token is expired
save access_token in user's session at the oauth server
send sharing data to the oauth server
It uses sinatra + rack:session + rack::session::sequel + sqlite to store sessions. It sends Set-Cookie: rack.session=id in each response
I am using 2 types of request: crossdomain ajax with jquery and usual request with window.open. I have a big security problem passing cookies to crossdomain ajax request.
No matter that server's response headers contains
Access-Control-Allow-Headers: *
chromium will throw security error:
Refused to set unsafe header "Cookie"
I want to avoid this problem by passing rack.session=id to post data and load it:
before "/twitter/connect.json" do
session = Rack::Session::something(params["rack.session"])
end
But I cant find in documentation how to do this
Rack::Session::Abstract::ID has an option called cookie_only that allows the session id to be passed in via the params. However, it defaults to true, and most session middleware implementations don't bother to override it.
Your best bet is probably to monkey patch Rack::Session::Abstract::ID to default cookie_only to false.
Rack::Session::Abstract::ID::DEFAULT_OPTIONS.merge! :cookie_only => false

Can an AJAX response set a cookie?

Can an AJAX response set a cookie? If not, what is my alternative solution? Should I set it with Javascript or something similar?
According to the w3 spec section 4.6.3 for XMLHttpRequest a user agent should honor the Set-Cookie header. So the answer is yes you should be able to.
Quotation:
If the user agent supports HTTP State Management it should persist,
discard and send cookies (as received in the Set-Cookie response
header, and sent in the Cookie header) as applicable.
Yes, you can set cookie in the AJAX request in the server-side code just as you'd do for a normal request since the server cannot differentiate between a normal request or an AJAX request.
AJAX requests are just a special way of requesting to server, the server will need to respond back as in any HTTP request. In the response of the request you can add cookies.
For the record, be advised that all of the above is (still) true only if the AJAX call is made on the same domain. If you're looking into setting cookies on another domain using AJAX, you're opening a totally different can of worms. Reading cross-domain cookies does work, however (or at least the server serves them; whether your client's UA allows your code to access them is, again, a different topic; as of 2014 they do).
Also check that your server isn't setting secure cookies on a non http request. Just found out that my ajax request was getting a php session with "secure" set. Because I was not on https it was not sending back the session cookie and my session was getting reset on each ajax request.

Resources