I discovered something new last night, which was painful like all good learning tends to be. I'm building a Cordova application for a client that - like most hybrid apps - can be run via a local web server for most of the development process. This particular project involves a complex dynamic form process that isn't Cordova-related at all. Later on we'll be adding in barcode scanning but for the foreseeable future I'm running it as a simple web page.
My application makes multiple XHR requests to the client's server for various things, and in order to make that work I'm using CORS. I won't need CORS once I switch to a proper hybrid app. I could also use Ripple too. But again - I just don't need this now at this point in the development.
Everything was kosher until I began to lock down some of the calls to require a session variable. In all my Cordova apps before I relied on the fact that sessions (cookie-based sessions) "just work" when doing XHR. If your back end server responds with cookies, then your front end code will respect that and send them back on future requests. This enables session management to work on your server.
Except when I used CORS! I couldn't understand why I kept getting an error saying that an earlier session variable wasn't defined. Like any good developer, I opened up my dev tools and examined the cookies being sent back and forth in my calls. (And again, if you have no idea how that is done, speak up in the comments.) I noticed right away that the session cookies were not sticking. So what was the problem?
If you read the docs for XHR and CORS you discover this little gem:
The most interesting capability exposed by both XMLHttpRequest and Access Control is the ability to make "credentialed" requests that are cognizant of HTTP Cookies and HTTP Authentication information. By default, in cross-site XMLHttpRequest invocations, browsers will not send credentials. A specific flag has to be set on the XMLHttpRequest object when it is invoked.
In English, the cookies won't go back and forth. Raise your hand if you knew that. Now lower it you liar. ;) Luckily it is easy enough to fix with a flag in the XHR object. AngularJS exposes it as a property, withCredentials.
But you then may run into yet another issue. My CORS header on the server was using Access-Control-Allow-Origin with a value of *. Basically, anyone and everyone can hit me. When you enable credentials on XHR, this is no longer allowed. Basically the browser is saying, "Sorry, this server is just too promiscuous for me." So for now, I've simply specified my local dev server in the origin. Once I get further down the line I'll probably remove CORS completely as it won't be needed for Cordova.
Archived Comments
I still have my hand up. : )
When I first experimented with CORS back in the Internet Explorer 8 days, I learned that with the IE8 XDomainRequest object, no authentication or cookies will be sent with the request. Internet Explorer 10+ supports CORS using XMLHTTPRequest.
http://blogs.msdn.com/b/iei...
Good to know IE10 supports it. :)
When my app was using Rhomobile 2 on windows mobile, I was using CORS (rhomobile runs a local ruby server, so you need to use CORS to access any other server).
I was not aware of that flag and the app seemed to work correctly, is it possible this handled automatically by jquery or something?
I think I may have had the issue when I tried to use Rhomobile 2 on android, maybe the Motorola browser I was using for Windows Mobile was hiding the issue...
Aniway, that was one of the many reasons why I switched to Cordova and I'm quite happy with that choice now.
Thanks for the info, that might be very usefull next time I'll have to deal with CORS.
It is entirely possible things are different on Windows Phone. I know I've seen odd issues there. As an example, at one point (not sure if it is true now), a WP PhoneGap app could not make an XHR request to an asset locally. Why? You know the whole JS on domain X can't hit Y unless you use CORS thing? Well the "location" for a PhoneGap app was being reported as "" (ie, nothing) and the XHR request was to a local file asset, and since "" != local file path, it was blocked.
Once you've gotten CORS working, there's another issue: 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 here: https://404it.no/en/blog/ja...