Background
(If you are familiar with CORS, you might skip to the Question at the end)
CORS [1] is a solution to allow browsers to permit access to resources from different domains. E.g. REST data backends using AJAX.
It is well observed on the Internet that Chrome (and Webkit friends) do not handle HTTP authentication prompts when such a resource demands it. E.g. [2] ( this is to prevent the browser showing an auth login dialog on for example, a Web-Mail sign-in page when an image tags load fails with a 401 and needs credentials. The user may be duped in to entering their webmail credentials)
Chrome's behaviour in this situation is to drop the response, cancelling the request almost silently.
In fact, Chrome will only let the response through normally if a 200 occurs; any other status code is swallowed and the AJAX call is aborted.
If one uses jQuery to perform an Ajax request, and the remote site responds with an HTTP 401 status code, the request is cancelled and the ajax completes with an error, but the 401 code is missing. It as if the connection died or a equivalent lower layer problem.
The only website I've seen which mentions this caveat of CORS specifically is [1]
Browers don't do a good job of reporting what went wrong when there is an error. For example, Firefox reports a status of 0 and an empty statusText for all errors. Browsers also report an error message to the console log, but this message cannot be accessed from JavaScript. When handling onerror, you will know that an error occurred, but not much else.
You can disable this security by using a chrome startup flag - just to test both the backend is functioning 'normally' and one sanity hasn't been unduly affected by the loss of proper status codes. See [2]
Problem
What if the backend and front-end client code is supposed to use the 401 as part of it's authentication process? - any failures are just just mangled into one "error" output.
For example: Upon issuing a request to authenticate - e.g. 2-legged OAuth token request -against a RESTful backend - which uses proper status codes - The client has no idea if:
- 401 The user was not authenticated.
- --- The connection failed.
- 400 There was a bad request.
- 500 The server has a problem.
- 207 There was no content after success.
A backend of ours which was written quite RESTfully, following as many best practices as was deemed cost effective at the time; one of these was relying on proper HTTP status codes. The Java REST Client we have working against has worked great.
Now I have begun creating a Javascript client, for embedding in webpages - specifically using CORS, and we have hit the problem in Chrome etc. (Note Firefox seems fine, and we generally don't care for IE at present.)
Question
What have people done to work around these issues?
Is there anything that can be done to make CORS more suitable for trusted backends?
Links
- CORS Tutorial: http://www.html5rocks.com/en/tutorials/cors/
- Chrome won't allow 401-triggered auth prompt for resources: http://code.google.com/p/chromium/issues/detail?id=81251
- --disable-web-security for Chrome: Disable same origin policy in Chrome
Now after much fiddling, I've managed to make it work. blush
There seems to be an awful lot of voodoo which makes up the exact scenario that ensures CORS will work in each browser, however having traced back numerous issues like:
Having stumbled upon what seemed to be a complete no-go, I ended up writing a CORS 4xx->200 wrapper as a jquery plugin,in an attempt to solve the issue. Debugging that plugin led me to my eventual fix.
Just ran into this issue. Setting the HTTP headers for the 401 response did the trick for me. The library I was using wasn't doing this properly without some customization. e.g.: