Previous Entry Share Next Entry
Cross-Origin Requests, and the user/password arguments of XmlHttpRequest.open
pokemon
unwiredben
Documenting this so it can be found if other people hit it in the future.

While tracking down a Enyo bug, https://enyojs.atlassian.net/browse/ENYO-645, I found an odd quirk of how cross-domain requests are done. Traditionally, you couldn't make a XHR request from a site on one domain into a site on another. However, browsers in the last few years have implemented a new scheme called CORS, short for

HTML5 Rocks has a great tutorial on it at http://www.html5rocks.com/en/tutorials/cors. For a simple GET request, all you have to do is add a header to what the server sends and your gold.

Things get more complicated if you want to do HTTP basic authentication with CORS. By default, a CORS request won't send credentials like cookies or the Authentication header. However, if you set the "withCredentials" property of the XmlHttpRequest object to true, they will be sent. However, that also triggers a pre-flight check from the browser where it makes an OPTIONS request without the credentials to verify that it will be able to actually make the second request. This is to prevent passing on credential data to a server that's not expecting CORS requests.

So, normally to do HTTP basic authentication, you can pass a username and password in your call to xhr.open. However, in the XHR level 2 spec, as seen at http://www.w3.org/TR/XMLHttpRequest/#the-open-method, using those arguments in a cross-origin setup will cause a failure. In Firefox 14, I didn't get the exception immediately, but instead it came when I used xhr.send(). I spent a long time trying to figure this out. What did work was directly specifying the "Authentication" header via xhr.setRequestHeader. I can only guess that the error flag gets set before any use of withCredentials can reset it back.

On the server side, I ended up needing these headers all to be returned in the OPTIONS request for this to work:

  • Access-Control-Allow-Origin: **exact value of request Origin header**
  • Access-Control-Allow-Credentials: true
  • Access-Control-Allow-Methods: GET
  • Access-Control-Allow-Headers: Authorization

?

Log in