26 December 2014
When creating a non-Web API ASP.NET MVC project using Individual Accounts, the generated template makes use of Forms Authentication. When logging in using Forms Authentication, a cookie is stored on the client’s machine and that cookie is included by the browser in each future request.
Instead of Forms Authentication, the Web API Individual Accounts project template includes code that makes use of bearer tokens for authentication / authorization. In this post, I will show how login using the bearer token can be achieved using AngularJS as the front-end framework.
I will be using Visual Studio Express 2013 for Web Update 4, Web API 2.2, and ASP.NET Identity 2.1.
A login request includes three things:
Upon a successful login, the login response will include the bearer token. This token should be included in the http headers of any authorized request. An http request is considered as authorized if a valid token is included.
The token is not a cookie, so the browser will not automatically send it in all future requests. Instead, the application should take care of including the token in each request. Later I will describe how AngularJS can do this using $http interceptors.
In this post, I will put the $http dependency on the controller, though of course the best practice is to put such dependencies in services. Here is an example controller:
myApp.controller('myCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.username = null;
$scope.password = null;
$scope.login = function () {
if (!$scope.username || !$scope.password) {
return;
}
var url = 'Token';
var data = 'username=' + $scope.username +
'&password=' + $scope.password +
'&grant_type=password';
var config = {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
};
$http.post(url, data, config).
success(function (data) {
console.log(data.access_token);
}).
error(function () {
// errors here, including:
// invalid_grant_type
// invalid username/password
});
};
}]);
A few things to note about the request parameters:
Let us store the token in sessionStorage.
myApp.controller('myCtrl', ['$scope', '$http', function ($scope, $http) {
// ...
$scope.login = function () {
// ...
$http.post(url, data, config).
success(function (data) {
sessionStorage.setItem('bearerToken', data.access_token);
}).
error(function () {
// ...
});
};
}]);
We can set up an $http interceptor to automatically include the token in requests.
myApp.config(['$provide', '$httpProvider', function ($provide, $httpProvider) {
$provide.factory('myInterceptor', ['$q', function ($q) {
return {
request: function (config) {
var bearerToken = sessionStorage.getItem('bearerToken');
if (bearerToken) {
config.headers['Authorization'] = 'Bearer ' + bearerToken;
}
return config || $q.when(config);
}
};
}]);
$httpProvider.interceptors.push('myInterceptor');
}]);
So once a token is present, an http header of Authorization: Bearer [token] will be included in all requests. [token] of course will be the value of the token you got after the successful login.
Without the token, we will not be able to make authorized requests. So “logging out” is simply a matter of removing the token.
myApp.controller('myCtrl', ['$scope', '$http', function ($scope, $http) {
// ...
$scope.logOut = function () {
sessionStorage.removeItem('bearerToken');
};
}]);
Note that sessionStorage will be cleared if the user closes the browser tab.
In this post I showed how to perform login using AngularJS + ASP.NET Web API using the bearer token. I showed how to correctly format the login http request and how to include the token in all http requests using an interceptor. I also showed how to log out.