4

I have two domains. I'm trying to access a JSON object from one domain through a page on another. I've read everything I could find regarding this issue, and still can't figure this out.

The domain serving the JSON has the following settings:

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, OPTIONS"
Header set Access-Control-Allow-Headers "origin, authorization, accept"

From my other domain, I'm calling the following:

$.ajax({
         type:'get',
         beforeSend: function(xhr) {
             var auth = // authentication; 
             xhr.setRequestHeader("Authorization", "Basic " + auth);
         }
         url:myUrl,
         dataType:'json',
         error: function(xhr, textStatus, errorThrown) { console.log(textStatus, errorThrown); }
      })

I know that 'auth' is initialized properly (logged and checked). However, this does not work. In Firefox's Console, I get Request URL: ...

Request Method:
OPTIONS

Status Code:
HTTP/1.1 401 Authorization Required

If I get rid of the beforeSend:... part, I see the following

Request Method:
GET

Status Code:
HTTP/1.1 401 Authorization Required

However, the domain serving JSON also can serve JSONP. I don't want to use this, mainly because the application will be running constantly on a dedicated browser, and I'm worried about this issue. More importantly, I would really like to know what is actually wrong with what I am doing. I know that for practical purposes there are various ways to overcome the JSONP memory leak (such as not using jQuery).

At any rate, when I did use JSONP, my code looked like this:

$.ajax({
    url:newUrl,
    dataType:'jsonp',
    jsonp:'jsonp'
}).done(function(d){console.log(d)})

This gets the following

Request Method:
GET

Status Code:
HTTP/1.1 200 OK

after it prompts me with an alert box for a username and password.

Is there a fundamental difference in the way jQuery handles JSONP requests as opposed to JSON requests? And if so, how can I fix this?

Thanks.

Edit: Here's what I did find.

Basically, because I need authentication, the GET request is sending an Authorization header. However, this is not a "simple" header, and so the browser is sending a pre-flight request (the OPTIONS). This preflight request doesn't have any authentication, though, and so the server was rejecting it. The "solution" was to set the server to let OPTIONS request not require authentication, and report an HTTP status of 200 to it.

Reference: http://www.kinvey.com/blog/item/61-kinvey-adds-cross-origin-resource-sharing-cors

mail-archive[.com]/c-user@axis.apache.org/msg00790.html (not allowed to post more links)

Unfortunately, the "solution" is only working on Firefox and not Chrome. Chrome simply shows the request in red, but doesn't give me any more info on why it failed.

Edit 2: Fixed on Chrome: The server I was trying to get data from had a security certificate which was not trusted. The preflight request on Chrome failed because of this. Solution superuser[.com]/questions/27268/how-do-i-disable-the-warning-chrome-gives-if-a-security-certificate-is-not-trust (not allowed to post more links)

Achal Dave
  • 4,079
  • 3
  • 26
  • 32
  • I think: jQuery JSONP loads the data as an external JavaScript (adds a ` – potench Jun 26 '12 at 02:24
  • I'm pretty sure the JSON load does a pre-fetch which will fail if loaded across domains. So you're probably not getting past the prefetch. – potench Jun 26 '12 at 02:26
  • http://stackoverflow.com/questions/9559947/cross-origin-authorization-header-with-jquery-ajax – Joe Jun 26 '12 at 14:55
  • May be you got wrong encoding user:pasdwd into base64? – Artem Oboturov Jun 27 '12 at 07:11
  • @potench: I assume that is the real reason. It seems that if a – Achal Dave Jun 27 '12 at 17:51

3 Answers3

5

Welp, now that I have enough rep a while later, I might as well answer this question and accept it.

When you attempt to send a GET json request to a server with headers, the browser first sends an OPTION request to make sure that you can access it. Unfortunately, this OPTION request cannot carry with it any authentication. This means that if you want to send a GET with auth, the server must allow an OPTION without auth. Once I did this, things started working.

Achal Dave
  • 4,079
  • 3
  • 26
  • 32
  • How did you do this? I'm experiencing a similar issue but with a POST request. It is returning OPTIONS and 401 Authorization Required. – CR47 Aug 14 '14 at 18:42
  • In my case, I was able to modify the server to allow OPTION requests without authentication, but I'm unsure if there's a better way... – Achal Dave Aug 14 '14 at 19:09
  • how did you modify the server? Is there an apache config? – CR47 Aug 14 '14 at 19:35
  • I don't recall exactly what I did (in fact, I think a coworker may have fixed it server side), but http://serverfault.com/questions/231766/returning-200-ok-in-apache-on-http-options-requests may help? – Achal Dave Aug 20 '14 at 22:29
1

Some examples available here may illustrate further how access control can be combined with CORS. Specifically the credentialed GET example. Access control requires that the request set the withCredentials flag to true on the XMLHttpRequest, and for the server handling the OPTIONS method to do two things:

  1. Set Access-Control-Allow-Credentials: true
  2. Not use a wildcard * in the Access-Control-Allow-Origin header. This has to be set to the origin exactly according to the MDN docs on HTTP access control (CORS).

Essentially, the thing processing the OPTIONS request needs to send back appropriate response headers so you can make that credentialed request.

In your question you stated that the service you are interacting with is returning Access-Control-Allow-Origin: *, which is not compatible with a credentialed cross-domain request. This needs to return the origin specifically.

The aforementioned MDN Http Access Control (CORS) documentation also links to the Server-Side Access Control documentation outlining how a server would potentially respond to various cross domain requests - including handling a cross domain credentialed POST request that requires you to send back the correct headers in response to the OPTIONS method. You can find that example here.

0

Why don't you try typing the URL you are fetching the JSON from into your browser and seeing what happens. It sounds like you literally just need to authenticate into this other website to access it.

If your site needs to work in other browsers like IE, you WILL need JSONP, by the way. The security won't allow the cross site request to work. The headers won't change that. I believe you will also need to add a security policy in your headers.

Joe
  • 7,922
  • 18
  • 54
  • 83
  • Tried it. Going to the URL pops open an alert asking for username and password, but the get request without jsonp does not. I do not need IE support. Thanks for the help, though... Any other ideas? – Achal Dave Jun 26 '12 at 01:16