Introduction
There are basically two different ways of implementing server side authentication for apps with a frontend and an API:
- The most adopted one, is Cookie-Based Authentication (you can find an example here) that uses server side cookies to authenticate the user on every request.
- A newer approach, Token-Based Authentication, relies on a signed token that is sent to the server on each request.
ASP.Net Web API
There is an open project JwtAuthForWebAPI implement a DelegatingHandler that creates a new ClaimsPrincipal based on the incoming token and assigns it to the current thread.
1. You can install the NuGet package for this library at https://www.nuget.org/packages/JwtAuthForWebAPI/.
2. Register the handler in your WebApiConfig.Register() method:
var tokenBuilder = new SecurityTokenBuilder();
var configReader = new ConfigurationReader();
var jwtHandlerSharedKey = new JwtAuthenticationMessageHandler
{
AllowedAudience = configReader.AllowedAudience,
Issuer = configReader.Issuer,
SigningToken = tokenBuilder.CreateFromKey(configReader.SymmetricKey),
PrincipalTransformer = new SimplePrincipalTransformer()
};
config.MessageHandlers.Add(jwtHandlerSharedKey);
3. Secure your controllers and/or their actions with the [Authorize] attribute - per standard ASP.NET authorization practices.
[Authorize]
public string Get(string id)
{
...
}
4. Assign a token when user login with correct password.
var configReader = new ConfigurationReader();
var key = Convert.FromBase64String(configReader.SymmetricKey);
var credentials = new SigningCredentials(
new InMemorySymmetricSecurityKey(key),
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
"http://www.w3.org/2001/04/xmlenc#sha256");
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, "bsmith"),
new Claim(ClaimTypes.GivenName, "Bob"),
new Claim(ClaimTypes.Surname, "Smith"),
new Claim(ClaimTypes.Role, "Customer Service")
}),
TokenIssuerName = "corp",
AppliesToAddress = configReader.AllowedAudience,
SigningCredentials = credentials
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
return tokenString;
Angular Client Side
1. The first step on the client side using AngularJS is to retrieve the JWT Token and have the JWT saved on sessionStorage.
myApp.controller('UserCtrl', function ($scope, $http, $window) {
$scope.user = {username: 'john.doe', password: 'foobar'};
$scope.message = '';
$scope.submit = function () {
$http
.post('/authenticate', $scope.user)
.success(function (data, status, headers, config) {
$window.sessionStorage.token = data.token;
$scope.message = 'Welcome';
})
.error(function (data, status, headers, config) {
// Erase the token if the user fails to log in
delete $window.sessionStorage.token;
// Handle login errors here
$scope.message = 'Error: Invalid user or password';
});
};
});
2.
Add Authorization header for every outgoing request:myApp.factory('authInterceptor', function ($rootScope, $q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
}
return config;
},
response: function (response) {
if (response.status === 401) {
// handle the case where the user is not authenticated
}
return response || $q.when(response);
}
};
});
myApp.config(function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
});
Reference:
1. Cookies vs Tokens. Getting auth right with Angular.JS
2. Techniques for authentication in AngularJS applications
3. JwtAuthForWebAPI