When implementing an Azure API App using MVC Web API with OAuth Bearer Token Authorization, we came across this error:
Response to preflight request doesn't pass access control check: Credentials flag is 'true', but the 'Access-Control-Allow-Credentials' header is ''. It must be 'true' to allow credentials. Origin 'http://domain.com' is therefore not allowed access.
|
This error is a result of an AJAX request to an Azure API App with Cross-origin resource sharing (CORS) support. We looked at the response headers and noticed that the 'Access-Control-Allow-Credentials header was actually blank which does not allow the browser to continue since it is a security policy. The code that makes the request is shown next:
$.ajax({
type: 'POST', async:true,
url: 'https://someapp.azurewebsites.net/token',
dataType: "json",
contentType: 'application/x-www-form-urlencoded; charset=utf-8',
xhrFields: {
withCredentials: true
},
headers: {
'Authorization': 'Basic ' + appInfo
},
success: function (result) {
var token = result.access_token;
//…
},
error: function (req, status, error) {
if (typeof(req) != 'undefined') {
var msg = status || req.responseJSON.error;
//…
}
}
});
|
The same code works OK when testing on the test environment (NO Azure). We can see how the headers for cross domain and credentials are included in the response headers. This confirms that outside of Azure, the CORS configuration in the application is correct.
Response Headers
Access-Control-Allow-Headers
Access-Control-Allow-Origin
Access-Control-Allow-Credentials
|
In Azure, we need to configure the CORS settings on the Azure Management UI which overrides any application CORS settings. This configuration outside of our web API application causes this problem with the header.
Since we are using OAuth bearer token security, we pass the client information as a header, and we do not use any type of cookies for security. This means that we do not need to use the withCredentials AJAX parameter.
withCredentials
Standard CORS requests do not send or set any cookies by default. In order to include cookies as part of the request, you need to set the XMLHttpRequest’s .withCredentials property to true. The server must also enable credentials by setting the Access-Control-Allow-Credentials response header to "true"
|
Once the withCredentials parameter is removed from the AJAX request, the Azure API App started to work properly. This is how the code looks now:
$.ajax({
type: 'POST', async:true,
url: 'https://someapp.azurewebsites.net/token',
dataType: "json",
contentType: 'application/x-www-form-urlencoded; charset=utf-8',
//xhrFields: {
// withCredentials: true
//},
headers: {
'Authorization': 'Basic ' + appInfo
},
success: function (result) {
var token = result.access_token;
//…
},
error: function (req, status, error) {
if (typeof(req) != 'undefined') {
var msg = status || req.responseJSON.error;
//…
}
}
});
|
The resolution is to configure the request in a way that matches the expected response header from the server. In this case, there was no need to exchange security over cookies since this is done using a token. This is the solution for this particular case, but there could be other root cause that manifest in a similar problem.