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 overe 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:
mail-archive[]/[email protected]/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[]/questions/27268/how-do-i-disable-the-warning-chrome-gives-if-a-security-certificate-is-not-trust (not allowed to post more links)
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 overe 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./blog/item/61-kinvey-adds-cross-origin-resource-sharing-cors
mail-archive[.]/[email protected]/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[.]/questions/27268/how-do-i-disable-the-warning-chrome-gives-if-a-security-certificate-is-not-trust (not allowed to post more links)
Share Improve this question edited Jun 29, 2012 at 16:45 Achal Dave asked Jun 26, 2012 at 0:49 Achal DaveAchal Dave 4,4193 gold badges27 silver badges32 bronze badges 5-
I think: jQuery JSONP loads the data as an external JavaScript (adds a
<script>
tag in your<header>
) and runs a temporarily generated jQuery function to parse the iningArray
of data once loaded. jQuery JSON loads the data as an XHR request expecting a JSON object as a result (so it's not loaded as a<script>
) which will fail with a CORS-error when loading across different origins and hence not get far enough to popup your user/pass alert box. – potench Commented Jun 26, 2012 at 2: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 Commented Jun 26, 2012 at 2:26
- stackoverflow./questions/9559947/… – Joe Commented Jun 26, 2012 at 14:55
- May be you got wrong encoding user:pasdwd into base64? – Artem Oboturov Commented Jun 27, 2012 at 7:11
- @potench: I assume that is the real reason. It seems that if a <script> tag is loaded, the server asks me for my username and password, but with a XHR request it doesn't. The JSON request does a preflight if I send credentials, and that preflight seems to fail despite the server allowing the "OPTIONS" method. For now, I'm going to have to stick with JSONP and see what happens. Joe: Thanks for the link, but generally following the directions didn't fix it. ArtemOboturov: I'm pretty sure I didn't... I even tried with an XHR request to [username]:[pass]@[server], and that didn't work either. – Achal Dave Commented Jun 27, 2012 at 17:51
3 Answers
Reset to default 5Welp, 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.
Some examples available here may illustrate further how access control can be bined 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:
- Set
Access-Control-Allow-Credentials: true
- Not use a wildcard
*
in theAccess-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 patible 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.
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.