Bugspray - XmlHttpRequest with HTTP Authentication

The problem

When making a XMLHttpRequest with HTTP authentication and using wrong credentials, some browser will prompt the user for credentials, which it should not do according to the current working draft of W3C. See quote below.

W3C working draft

4.6.3 The send() method
...
If the user agent supports HTTP Authentication and Authorization is not in the list of author request headers, it should consider requests originating from the XMLHttpRequest object to be part of the protection space that includes the accessed URIs and send Authorization headers and handle 401 Unauthorized requests appropriately. If authentication fails, and request username and request password are both null, user agents should prompt the end user for credentials. If authentication fails, and request username and request password are provided, user agents must not prompt the end user for credentials.

Browsers that fail the test below

  1. Firefox 3.5.3
  2. Google Chrome 3.0.195.21

Some previous interests in this behavior

2008 2007 2006 (relies on 400 response when wrong credentials is used)


The test

Form that uses XMLHttpRequest with HTTP authentication

The correct username is 'test' and the correct password is 'test'. When the user presses the Sign in button in the form below, he/she should never be prompted for authentication. Note try wrong credentials first, correct credentials are cached.

Username:
Password:

Output:

Relevant JavaScript

// <form id="login" onsubmit="return login()">
function login()
{
	if(document.getElementById("username").value == "" || document.getElementById("passwd").value == "" )
	{
		alert('Fill out both username and password, please...');
		return false;
	}
	var xhr = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
	xhr.open("get", "http://codereaper.com/bugspray/javascript/xmlhttprequest/httpauthentication/callback/", false, document.getElementById("username").value, document.getElementById("passwd").value);
	xhr.send("");
	if (xhr.status == 200) 
	{
		document.getElementById("console").innerHTML = xhr.responseText;
	}
	else
	{
		alert('Wrong credentials...');
		document.getElementById("console").innerHTML = xhr.responseText;
	}
	return false;
}

PHP taking care of the response

$user = (empty($_SERVER['PHP_AUTH_USER'])) ? '' : $_SERVER['PHP_AUTH_USER'];
$passwd = (empty($_SERVER['PHP_AUTH_PW'])) ? '' : $_SERVER['PHP_AUTH_PW'];

if($user == $passwd && $user == 'test')
{
	echo 'Authorized.';
}
else
{
	header('WWW-Authenticate: Basic realm="My Realm"');
	header('HTTP/1.0 401 Unauthorized');
	echo 'Unauthorized!';
}