Using XMLHttpRequest to get cross-origin (CORS) resource requiring Basic Authorization

mrputter Source

The Title sums up the basic request / context pretty well. I am trying to use JavaScript to retrieve a web resource using XMLHttpRequest. The request is cross-origin, thus I am using CORS. The resource is also being made over HTTPS (using Basic authentication), so I am having to send that auth header.

As far as I can tell, I've set everything up correctly, but I'm obviously missing something because I'm still getting back a Response for preflight has invalid HTTP status code 401.

And I don't know why.


My JS code follows:

var url = <MyURL>;

var xhr = new XMLHttpRequest();

xhr.open( 'GET', url, true );
xhr.withCredentials = true;
xhr.setRequestHeader( 'Authorization', 'Basic ' + window.btoa( <MyUsername> + ':' + <MyPassword> ) );
xhr.onreadystatechange = function() {
    console.log( 'readyState: ' + xhr.readyState + ', status: ' + xhr.status );
    if (xhr.readyState == 4) {
        if (xhr.status == 200) {
            document.getElementById( 'filecontent' ).value = 'HTTP 200 Success:\n' + xhr.responseText;
        } else if (xhr.status == 401) {
            document.getElementById( 'filecontent' ).value = 'HTTP 401 Unauthorized:\n' + x.getAllResponseHeaders();
        } else if (xhr.status == 0) {
            document.getElementById( 'filecontent' ).value = 'CORS failed.';
        }
    }
}
xhr.send( null );

And the request/response headers, as reported by Chrome, follow. (I'm running the code from inside a Python SimpleHTTPServer session, so that I can actually have an origin that is not null, just to be on the safe side.)

Request/Response Headers for XMLHttpRequest (transcript below)

Everything looks right? The request Origin header matches the response Access-Control-Allow-Origin header (http://127.0.0.1:9000). The Access-Control-Allow-Methods header includes OPTIONS, which is the request method I'm making (since this is the preflight stage).

But the status code is still coming back as 401 Unauthorized (which isn't even getting passed back to the XMLHttpRequest object, which only ever sees status := 0, and trying to run any kind of getResponseHeader() call just returns null).

For what it's worth, here's the console output. (Not very interesting other than the fact that the OPTIONS call returns 401 Unauthorized, and I then get a Failed to load <MyURL> with the aforementioned Response for preflight has invalid HTTP status code 401.)

Console output for XMLHttpRequest

The "obvious" answer would seem to be that the username/password are wrong, but if I make the request directly from the URL bar, it works (when typing in the same username & password), so that doesn't seem to be it. The only difference being that it doesn't need to make a preflight request (since it doesn't have to deal with CORS).

So I feel like I'm missing something obvious here, but uh... help?


Transcript for headers:

General

Request URL: <MyURL>
Request Method: OPTIONS
Status Code: 401 Unauthorized
Remote Address: <MyIP>:443
Referrer Policy: no-referrer-when-downgrade

Response Headers

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: null
Connection: keep-alive
Content-Length: 606
Content-Type: text/html
Date: Wed, 13 Jun 2018 21:04:09 GMT
Server: nginx/1.10.3 (Ubuntu)
WWW-Authenticate: Basic realm="<MyRealm>"

Request Headers

Provisional headers are shown
Access-Control-Request-Headers: authorization
Access-Control-Request-Method: GET
Origin: null
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36
javascripthttpscorsxmlhttprequesthttp-status-code-401

Answers

comments powered by Disqus