I am currently working on an problem with a login page for an AngularJS app. The login page uses the
$http service to submit the username and password using Basic authentication (
Authorization: Basic (username and password in base 64)) to a Web service that may or may not be running on the same server that the webapp is hosted on. If authentication succeeds, the server returns a response with status 200 OK; otherwise, it returns a 401 Not Authorized. We have an error function to gracefully handle this error condition, but before it is even called, the browser by default shows a modal dialog for the user to enter his or her username and password. How can I prevent this?
I've looked at several sources, including the W3 standards for XHR.send(), for help, and my findings show that in Firefox and Chrome, the browser dialog pops up after a 401 response to an XHR call when all of the following are true:
1) The request is "same-origin" (which it is in the cases where the web service is running on the same server that serves the webapp)
2) The response includes the header
WWW-Authenticate: Basic [some realm] or
WWW-Authenticate: Digest [some realm] (our web service returns the former)
3) The request was not made by specifically setting a username and password in the XHR object whose
send() method was called.
I found a test site (which SO won't let me link to) that exhibits the desired behavior for 401 responses (no modal login box). It meets the first two conditions but avoids meeting the third, apparently because it sets the XHR object's username and password by sending them as arguments #4 and 5 to its
The problem is that our site's login service doesn't itself call
XmlHttpRequest.open() to pass the username and password; instead, it creates the Authorization header itself and passes it in the headers collection of a params object to
$http. By inspecting the source of angular.js, I found that $http then proceeds to call
open() with only three parameters.
Does Angular provide a way to have
$http call the 5-parameter overload of open(), or otherwise prevent this login dialog from showing up? If not, I can only think of a few workarounds:
1) Somehow decorate
$http to enforce calling the 5-parameter overload of
open() if a username and password are provided
2) Somehow use
$httpBackend to achieve the same as #1 (though the documentation discourages developers from using
$httpBackend so I'm not sure if this is a good idea or even possible)
$http and have my login service create and send the XHR itself
4) Alter the server so it doesn't return the
WWW-Authenticate: Basic header (least desirable)
Is there a well-known or "right" way to work around this problem?