P
P
pxx2013-06-10 14:11:53
JavaScript
pxx, 2013-06-10 14:11:53

CORS + Basic Authentication not working in most browsers

I'm trying to get JSON from an external domain. Everything would be fine, but it is protected using Basic Authentication, which for some reason complicates access for many browsers.
It is not possible to freely rotate the external domain, you can configure it, but it is administered on the client side and there is no way to constantly pull it. Therefore, I had to create a test bench in a vacuum.

There is the following code on the external domain:

<?php
  header("Access-Control-Allow-Credentials: true");
  header("Access-Control-Allow-Origin: http://clientdomain");
?>
{ "result": "ok" }


The following code on the client:
$('button').click(function(){
  $.ajax({
    url: 'http://overestimated.info/script.php',
    type: 'GET',
    crossDomain: true,
    dataType: 'json',
    username: 'user',
    password: 'user',
    success: function(x, status){
      console.log(JSON.stringify(x));
    },
    error: function(x, status, error){
      console.log(status);
      console.log(error);
    }
  });
});


In Chrome and Safari, the code works as expected and receives the required JSON. In other browsers, sadness begins: according to Fiddler, the request for an external domain does not leave at all, and an error occurs in the console.
Opera : status: "error", error: ""
IE10 : status: "error", error: "InvalidAccessError"
FF : status: "error", error: "[Exception… "Access to restricted URI denied" code: "1012 " nsresult: "0x805303f4 (NS_ERROR_DOM_BAD_URI)" location: " clientdomain/js/lib/jquery-1.10.0.min.js Line: 6"] { constructor=DOMException, code=1012, INDEX_SIZE_ERR=1, more...} "(there is a whole object)

Googled a lot, tried a lot, but I can't get through. There are tips to include withCredentials in the request
xhrFields: {
  withCredentials: true
}

или

beforeSend: function(xhr){
  xhr.withCredentials = true;
},


This does not help, the request still breaks off in the browser before being sent.
Here is an example . jsfiddle for some reason does not like IE and Opera, but in Chrome, Safari and Firefox everything is worked out as I described.

Please help me understand what's going on.

PS: Basic Auth is not configured on the test bench, but in fact it is not needed: either it works as it should, or it is rejected even before the request is sent.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
M
merlin-vrn, 2013-06-11
@pxx

In general, I tend to think that this is a bug in jQuery. I wrote a code for CORS with Basic Auth "hands" without jQuery, it works at least in Fx 10 and 17 and in Opera 12.10
The code is as follows:
on the client −

<!DOCTYPE html>
<html><head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>CORS testing</title>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {
    document.getElementById("1").addEventListener("click", function() {
        var xhr = new XMLHttpRequest();
        xhr.onload = function(e) {
            document.getElementById("2").textContent = xhr.responseText;
        };
        xhr.open("GET", "http://dev.merlin-vrn.tk/cors/api.php", true);

//        xhr.withCredentials = true;
        xhr.setRequestHeader("Authorization", "Basic dGVzdHVzZXI6dGVzdHBhc3N3b3Jk");

        xhr.send();
    }, false);
}, false);
</script>

</head><body>

<button id="1">Click me</button>
<div id="2"></div>

</body></html>


on the north -
<?php

if (isset($_SERVER['HTTP_ORIGIN']))
    header("Access-Control-Allow-Origin: $_SERVER[HTTP_ORIGIN]");

if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {                                                                                                                        
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))                                                                                                        
        header("Access-Control-Allow-Methods: $_SERVER[HTTP_ACCESS_CONTROL_REQUEST_METHOD]");                                                                         
                                                                                                                                                                      
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))                                                                                                       
        header("Access-Control-Allow-Headers: $_SERVER[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]");                                                                        
} else {                                                                                                                                                              
    header('WWW-Authenticate: Basic realm="API"');                                                                                                                    

    header("Content-Type: application/json");

    if (isset($_SERVER['PHP_AUTH_USER']) && $_SERVER['PHP_AUTH_USER'] == "testuser" && isset($_SERVER['PHP_AUTH_PW']) && $_SERVER['PHP_AUTH_PW'] == "testpassword") {
        header('HTTP/1.1 200 OK');
        echo '{"result": "ok"}';
    } else {
        echo '{"result": "noauth"}';
    }
}

file_put_contents("api-log.txt", "$_SERVER[REQUEST_METHOD] $_SERVER[REQUEST_URI] $_SERVER[SERVER_PROTOCOL]\n", FILE_APPEND);
file_put_contents("api-log.txt", print_r($GLOBALS, true), FILE_APPEND);
file_put_contents("api-log.txt", "\n\n", FILE_APPEND);

?>


The logging at the end of this script is just for testing convenience. Live can be seen here .
PS gentlemen, tell me a highlighter for habr, huh?

Q
quozd, 2013-06-10
@quozd

For IE, you need to specify

$.support.cors = true;

Otherwise, it will not work, I will not say anything about the Opera, because I have not tried it.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question