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