I have an angularjs HTML client to a WebApi project. When I test the APIs via POSTMAN or other REST Client, it seems that everything is ok.
When I start using browsers with my angularjs client, browsers always start preflight requests with OPTIONS. There, my WebAPI always answers 400 Bad Request - I am still on a "/api/token" phase.
I have already attached every single point of my WebAPI project to the debugger. I have also changed several points according to several answers here in SO on how to enable CORS. Some of them I have already tried: changing web.config to add headers enabling cors on every request, adding cors to WebApi startup, enabling cors at "/token" overridden functions.
Here is what I got so for:
Angularjs TypeScript call to "/api/token":
logIn = (userName: string, userPassword: string): ng.IPromise<void> => {
var postData = {
"grant_type": "password",
"client_id": this.appConfiguration.ClientId,
"client_secret": this.appConfiguration.ClientSecret,
"username": userName,
"password": userPassword
};
return this.$http.post<models.LoggedUserModel>('http://local.web.api/api/token', $.param(postData), {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then((result) => {
this.localStorageService.set('Auth', result);
this.goHome(true);
}).catch((error) => {
console.warn(error);
});
}
Here is the only function that is called on my WebApi:
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// handle cors requests
if (!string.IsNullOrEmpty(context.OwinContext.Request.Headers.Get("Origin")))
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new string[] { "*" });
}
try
{
// retrieve clientId and clientSecret from request body
string clientId;
string clientSecret;
if (context.TryGetFormCredentials(out clientId, out clientSecret))
{
// here it comes our application specific security code....
}
else
{
// this is part of enabling CORS..
if (context.Request.Method.ToUpper() == "OPTIONS")
{
// it returns OK to preflight requests having an empty body
context.Validated();
}
}
}
finally
{
// log stuff...
}
}
If I just left OWIN Cors stuff, adding headers and calling ´context.Validated()´ it all continues the same. Here is what I get:
Firefox Network Tab:
--------------------
Request URL: http://local.web.api/api/token
Request method: OPTIONS
Remote address: 127.0.0.1:80
Status code: 400 Bad Request
Version: HTTP/1.1
Request headers:
----------------
Host: local.web.api
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.7,pt-BR;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization
Origin: http://local.web.client
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Response headers:
-----------------
Access-Control-Allow-Origin: *
Cache-Control: no-cache
Content-Length: 34
Content-Type: application/json;charset=UTF-8
Date: Tue, 22 Dec 2015 15:24:23 GMT
Expires: -1
Pragma: no-cache
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
I would really appreciate some ideas of where to got. This is brand new to me, and I do operate some other WebApi projects + angularjs.
Ok, that's is terrible but I found the issue.
I am using a http interceptor on angularjs that would automatically check for a logged user and add an Authorization
header with the Bearer
token when needed. Problem is I was doing it wrongly.
I created a new property in the config
object, bypassToken
as boolean, that would be the flag to add or not the Authorization
header. Removing this actually fixed the code. Not sure why, but analyzing the request now I can see that all headers are actually sending as expected: with the Content-Type
which was not being filled on the first case correctly. Weird though no warning was thrown by angularjs.
// http auth interceptor
angularApplication.factory('httpAuthInterceptor', ['$rootScope', '$injector', '$location', ($rootScope, $injector, $location): ng.IHttpInterceptor => {
var $q: ng.IQService = $injector.get('$q');
var localStorageService: ng.local.storage.ILocalStorageService = $injector.get('localStorageService');
return {
request: (config: ng.IRequestConfig): ng.IRequestConfig => {
// check if headers are present
config.headers = config.headers || {};
// the error was here! I was trying to add properties to config that I think angular was not expecting
// removing this line solved the issue
// if (!config.bypassToken) {
// check if user is logged in
var loggedUserInfo = localStorageService.get<models.LoggedUserInfoModel>('Auth');
if (loggedUserInfo) {
config.headers['Authorization'] = 'Bearer ' + loggedUserInfo.access_token;
}
return config;
},
responseError: (rejection) => {
// check if user is logged in
var loggedUserInfo = localStorageService.get<models.LoggedUserInfoModel>('Auth');
if ((rejection.status === 401) && (loggedUserInfo)) {
// if so, then the user must login againd
localStorageService.remove('Auth');
$location.path('/home');
console.error(rejection);
}
return $q.reject(rejection);
}
};
}]);
I appreciate your help.
I am only posting this here in case someone faces a similar issue.
Don't mess with the config
object!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With