REST API HTTP response codes

Hi,

I am testing the REST API with Javascript and PHP. I tested three scenarios to get the token from http://localhost:8080/app/rest/v2/oauth/token:

  1. using the correct header and username and password
  2. omitted grant_type from the header
  3. using the correct header with wrong username and password.

In the first scenario, when I do everything correctly, I receive a response with the 200 OK status code which is fine.
In the second scenario, I get a 400 Bad Request response as expected.
In the third scenario, I also get a 400 Bad Request response. Why is the API not sending a 401 Unauthorized response when the username and/or password is incorrect?

Here is the Javascript code


function login() {
    var userLogin = $('#loginField').val();
    var userPassword = $('#passwordField').val();
    $.post({
		  url: 'http://localhost:8080/app/rest/v2/oauth/token',
		headers: {
			'Authorization': 'Basic Y2xpZW50OnNlY3JldA==',
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        dataType: 'json',
        data: {username: userLogin, password: userPassword},
        success: function (data) {
            oauthToken = data.access_token;
            $('#loggedInStatus').show();
            $('#loginForm').hide();
			alert(data.access_token);
        },
		error: function (XMLHttpRequest, textStatus, errorThrown) {
			alert(XMLHttpRequest.responseText);	
		}
    })
}

Here is the PHP code:


$url = 'http://localhost:8080/app/rest/v2/oauth/token';

$username = $_POST["username"];
$password = $_POST["password"];
 
$data = array('grant_type' => 'password', 'username' => $username, 'password' => $password);

$client = "client";
$secret = "secret";

$header = "Content-type: application/x-www-form-urlencoded\r\n" . "Authorization: Basic " . base64_encode("$client:$secret");

// use key 'http' even if you send the request to https://...
$options = array(
    'http' => array(
        'header'  => $header,
        'method'  => 'POST',
        'content' => http_build_query($data)
    )
);
$context  = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { 
	var_dump($http_response_header); 

} else {
	var_dump($http_response_header);
	echo $result;
	
}

With the Javascript code above, XMLHttpRequest.responseText will contain {“error”:“invalid_request”,“error_description”:"Missing grant type} because I did not specify the grant_type in the header. So one can use XMLHttpRequest.responseText to narrow down the “bad request” response to either an invalid request (second scenario) or bad credentials (third scenario). It would be awesome if someone has a solution for the PHP implementation if it is not possible for the API to return a 401 error.

Hi,

According to the OAuth2 specification, in case of invalid resource owner credentials (the 3rd of your cases) the server must respond with the “invalid_grant” error with code 400 . See here: RFC 6749: The OAuth 2.0 Authorization Framework

Thanks, that explains it.

Here is a PHP solution:


$url = 'http://localhost:8080/app/rest/v2/oauth/token';

$ch = curl_init($url);

$username = $_POST["username"];
$password = $_POST["password"];
 
//TODO: move these strings to a config file
$client = "client";
$secret = "secret";

$auth = "Authorization: Basic " . base64_encode("$client:$secret");
$data = array('grant_type' => urlencode('password'), 'username' => urlencode($username), 'password' => urlencode($password));

//url-ify the data for the POST
$fields_string = "";
foreach($data as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
rtrim($fields_string, '&');


curl_setopt($ch,CURLOPT_HTTPHEADER,array($auth,
    'Content-Type: application/x-www-form-urlencoded'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, count($data));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);

$str = curl_exec($ch);
curl_close($ch); 

var_dump($str);