Web API Token Based Authentication With Angular - Part Two

In my previous article, I explained how to implement Token Based Authentication in Web API. This article will demonstrate how to implement Token Based Authentication in AngularJS application.

Security is the main concern when you are creating a client application. In AngularJS, you have to take care when sending your credentials from the client side. You don’t want to send credentials with every request. When you use the Token Based Authentication, you do not need to send secure data every time to the server. You have to send your credentials once and the server will return a secure token. This token could be saved at client side and the next request will use this token to process a request. You can define expiry of the token as well.

So, let us move to the demonstration part. Create an empty solution in Visual Studio and set up all required as in the following image. We will cover every file’s task one by one with the following demonstration.

Angular

First, you have to create app.js at the root level, which contains the application module and its dependencies like routing module. Here, you need to create a constant named “appSetting” and define the base service URL that will be used to fetch data from the server [I am using localhost URL for this demonstration]. To implement UI routing, we are using “ui-router” as a dependency and respectively defining a different route.

Every time we send a request, we get a response from the server. Before processing any request, we have to modify the data or need to add some data like headers data with the request. When the response data returns, it could be anything; it might be some exceptions also. If anything happens wrong, then we have to handle everything, so for this, we have added an Interceptor named as “AuthInterceptor”.

APP.JS

  1. (function () {  
  2.     'use strict';  
  3.   
  4.     var app = angular.module("mukeshApp", ['ui.router']);  
  5.   
  6.     app.constant("appSetting", {  
  7.         apiBaseUrl: "http://localhost:58238/"  
  8.     });  
  9.   
  10.     app.config(['$stateProvider''$urlRouterProvider''$locationProvider'function ($stateProvider, $urlRouterProvider, $locationProvider) {  
  11.         $urlRouterProvider.otherwise('/home');  
  12.         $locationProvider.hashPrefix('');  
  13.   
  14.         $stateProvider.state('default', {  
  15.             url: '/',              
  16.             templateUrl: '/app/components/home/index.html',  
  17.             controller: 'HomeCtrl'  
  18.         })  
  19.         .state('home', {  
  20.             url: '/home',  
  21.             templateUrl: '/app/components/home/index.html',  
  22.             controller: 'HomeCtrl'  
  23.         })  
  24.         .state('login', {  
  25.             url: '/account/login',  
  26.             templateUrl: '/app/components/login/index.html',  
  27.             controller: 'LoginCtrl'  
  28.         });  
  29.     }  
  30.     ]);  
  31.     app.config(['$httpProvider'function ($httpProvider) {  
  32.         $httpProvider.interceptors.push('AuthInterceptor');  
  33.     }]);  
  34.   
  35.     app.config(['$qProvider'function ($qProvider) {  
  36.         $qProvider.errorOnUnhandledRejections(false);  
  37.     }]);  
  38.   
  39. })();  

AUTHINTERCEPTOR.JS

Here, AuthInterceptor will handle every request and response as well as request error and response error. If any error returns, the application moves to the login page, otherwise it will redirect to home page.

If the user is already logged in and a validated token has already been added in session, then for the next request, we will not send credentials to the server. We will pick the token from session item and add token with the request.

  1. (function (app) {  
  2.   
  3.     app.factory('AuthInterceptor', ['$log''$state''$q'function ($log, $state, $q) {  
  4.         $log.debug('$log is here to show you that this is a regular factory with injection');  
  5.   
  6.         var authInterceptor = {  
  7.             request: function (config) {  
  8.                 var accessToken = sessionStorage.getItem('accessToken');  
  9.                 if (accessToken == null || accessToken == "undefined") {  
  10.                     $state.go("login");  
  11.                 }  
  12.                 else {  
  13.                     config.headers["Authorization"] = "bearer " + accessToken;  
  14.                 }  
  15.                 return config;  
  16.             },  
  17.   
  18.             requestError: function (config) {  
  19.                 $state.go("login");  
  20.                 return config;  
  21.             },  
  22.   
  23.             response: function (res) {  
  24.                 return res;  
  25.             },  
  26.   
  27.             responseError: function (res) {  
  28.                 if (res.status == "401") {  
  29.                     $state.go("login");  
  30.                 }  
  31.                 if (res.status == "400") {  
  32.                     $state.go("login");  
  33.                 }  
  34.                 if (res.status == "403") {  
  35.                     $state.go("login");  
  36.                 }  
  37.                 if (res.status == "404") {  
  38.                     $state.go("login");  
  39.                 }  
  40.                 $q.reject(res)  
  41.                 return res;  
  42.             }  
  43.         };  
  44.   
  45.         return authInterceptor;  
  46.     }]);  
  47.   
  48. })(angular.module("mukeshApp"));  

EMPLOYEESERVICE.JS

In the previous part, we have created a Web API Employee Controller which has GetEmployees(). It returns employees data. So, to get employee data from the database, we are creating a service named “EmployeeService”. This will make an API call which we have already made in my previous part.

  1. (function (app) {  
  2.   
  3.     'use strict';  
  4.   
  5.     app.factory("EmployeeService", ["$http""appSetting""$q", EmployeeService]);  
  6.   
  7.     function EmployeeService($http, appSetting, $q) {  
  8.           
  9.         this.GetAll = function () {  
  10.             var deffered = $q.defer();  
  11.              
  12.             var query = $http.get(appSetting.apiBaseUrl + "api/employee/GetEmployees");  
  13.   
  14.             return query.then(function (response) {  
  15.                 deffered.resolve(response.data);  
  16.                 return deffered.promise;  
  17.             }, function (response) {  
  18.                 deffered.reject(response);  
  19.                 return deffered.promise;  
  20.             });  
  21.         };  
  22.   
  23.         return {  
  24.             GetAll: this.GetAll  
  25.         }  
  26.     };  
  27.   
  28. })(angular.module("mukeshApp"));  

LOGINSERVICE.JS

This service will be used to log in with Server using provided credentials. Please don’t forget to pass grant_type = “password”.

  1. (function (app) {  
  2.   
  3.     'use strict';  
  4.     app.factory("LoginService", ["$http""appSetting", LoginService]);  
  5.   
  6.     function LoginService($http, appSetting) {  
  7.   
  8.         this.login = function (userData) {  
  9.   
  10.             var response = $http({  
  11.                 url: appSetting.apiBaseUrl + 'token',  
  12.                 method: 'POST',  
  13.                 data: $.param({  
  14.                     grant_type: userData.grant_type,  
  15.                     username: userData.username,  
  16.                     password: userData.password  
  17.                 }),  
  18.                 headers: { 'Content-Type''application/x-www-form-urlencoded' }  
  19.             });  
  20.             return response;  
  21.         };  
  22.   
  23.         return {  
  24.             login: this.login  
  25.         }  
  26.     };  
  27.   
  28. })(angular.module("mukeshApp"));  

HOMECTRL.JS

To fetch and display the data on home page, we are creating HomeCtrl controller. Here, getAllEmployees function will get the all employee data and bind with $scope.employees.

  1. (function (app) {  
  2.     'use strict';  
  3.   
  4.     app.controller('HomeCtrl', ['$scope''EmployeeService', HomeCtrl]);  
  5.   
  6.     function HomeCtrl($scope, EmployeeService) {  
  7.   
  8.         $scope.getAllEmployees = function () {  
  9.             EmployeeService.GetAll().then(function (result) {  
  10.                 $scope.employees = result;  
  11.             }, function (error) {  
  12.                 console.log("Bad Request Process");  
  13.             });  
  14.         };  
  15.   
  16.         $scope.init = function () {  
  17.             $scope.getAllEmployees();  
  18.         };  
  19.   
  20.         $scope.init();  
  21.     };  
  22. })(angular.module("mukeshApp"));  

Once you will get data, you have to show it to the user interface. So, as  in the following, you have to use “ng-repeat” to use the rendered data as table format.

  1. <div class="row">  
  2.     <div class="col-lg-2">  
  3.     </div>  
  4.     <div class="col-lg-8">  
  5.         <h2>Token Based Authentication in AngularJS </h2>  
  6.         <br />  
  7.         <div class="panel panel-default">  
  8.             <div class="panel-heading">  
  9.                 Employee List  
  10.             </div>  
  11.   
  12.             <div>  
  13.                 <table width="100%" class="table table-striped table-bordered table-hover" id="dataTables-example">  
  14.                     <thead>  
  15.                         <tr>  
  16.                             <th>ID</th>  
  17.                             <th>Name</th>  
  18.                             <th>Address</th>  
  19.                         </tr>  
  20.                     </thead>  
  21.                     <tbody>  
  22.                         <tr ng-repeat="emp in employees">  
  23.                             <td>{{emp.id}}</td>  
  24.                             <td>{{emp.name}}</td>  
  25.                             <td>{{emp.address}}</td>  
  26.                         </tr>  
  27.                     </tbody>  
  28.                 </table>  
  29.             </div>  
  30.         </div>  
  31.     </div>  
  32. </div>  

LOGINCTRL.JS

It will take credentials from user screen and create user object, which also contains grant_type as “password”. Once you log in successfully, you can set token in sessionStorage for further use and redirect to home page.

  1. (function (app) {  
  2.     'use strict';  
  3.   
  4.     app.controller('LoginCtrl', ['$scope''$state''LoginService', LoginCtrl]);  
  5.   
  6.     function LoginCtrl($scope, $state, LoginService) {  
  7.   
  8.         $scope.user = [];  
  9.         $scope.userName = "";  
  10.         $scope.password = "";  
  11.         $scope.userDisplayName = "";  
  12.         $scope.isAuthenticated = true;  
  13.         $scope.logout = function () {  
  14.   
  15.         };  
  16.   
  17.         $scope.loggedIn = function () {  
  18.   
  19.             $scope.user = {  
  20.                 grant_type: 'password',  
  21.                 username: $scope.userName,  
  22.                 password: $scope.password  
  23.             };  
  24.             if ($scope.userName == "" || $scope.password == "") {  
  25.                 $scope.isAuthenticated = false;  
  26.                 $state.go("login");  
  27.             }  
  28.             else {  
  29.                 var promise = LoginService.login($scope.user);  
  30.   
  31.                 promise.then(function (resp) {  
  32.                     if (resp.data != null) {  
  33.                         if (resp.data.error == "invalid_grant") {  
  34.                             $scope.isAuthenticated = false;  
  35.                             $state.go('login');  
  36.                         }  
  37.                         else {  
  38.   
  39.                             $scope.isAuthenticated = true;  
  40.                             sessionStorage.setItem('userName', $scope.userName)  
  41.                             sessionStorage.setItem('accessToken', resp.data.access_token)  
  42.                             sessionStorage.setItem('userName', $scope.userName)  
  43.                             $state.go('home');  
  44.                         }  
  45.                     } else {  
  46.                         $scope.isAuthenticated = false;  
  47.                         $state.go("login");  
  48.                     }  
  49.                 }, function () {  
  50.   
  51.                     $scope.isAuthenticated = false;  
  52.                     $state.go("login");  
  53.   
  54.                 }, function () {  
  55.                     console.log("C");  
  56.                     $scope.isAuthenticated = false;  
  57.                     $state.go("login");  
  58.   
  59.                 });  
  60.   
  61.             }  
  62.         };  
  63.   
  64.   
  65.     };  
  66. })(angular.module("mukeshApp"));  

Following is the template for login page.

  1. <div class="col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2">  
  2.   
  3.     <div class="panel panel-success">  
  4.         <div class="alert alert-danger" ng-if="!isAuthenticated">  
  5.             <strong>Oh Sorry!</strong> Incorrect user name or password, try again.  
  6.         </div>  
  7.         <div class="panel-heading">  
  8.             <div class="panel-title center">Sign In</div>  
  9.             <div class="panel-body">  
  10.   
  11.                 <form class="form-horizontal" role="form">  
  12.                     <div class="input-group input-username">  
  13.                         <span class="input-group-addon"></span>  
  14.                         <input type="text" class="form-control" name="username" placeholder="username" ng-model="userName" autofocus>  
  15.                     </div>  
  16.                     <div class="input-group input-password">  
  17.                         <span class="input-group-addon"></span>  
  18.                         <input type="password" class="form-control" name="password" placeholder="password" ng-model="password">  
  19.                     </div>  
  20.                     <div class="input-group checkbox-remember">  
  21.                         <div class="checkbox">  
  22.                             <label><input id="login-remember" type="checkbox" name="remember" value="1"> Remember me</label>  
  23.                         </div>  
  24.                     </div>  
  25.                     <div class="form-group login-button">  
  26.                         <div class="col-sm-12 controls">  
  27.                             <input type="submit" class="btn btn-success" value="Login" ng-click="loggedIn()" />  
  28.                         </div>  
  29.                     </div>  
  30.   
  31.                 </form>  
  32.             </div>  
  33.         </div>  
  34.   
  35.     </div>  

Here is the final index.html that contains all the references.

  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4.     <base href="/" />  
  5.     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  6.     <!-- Meta, title, CSS, favicons, etc. -->  
  7.     <meta charset="utf-8">  
  8.     <meta http-equiv="X-UA-Compatible" content="IE=edge">  
  9.     <meta name="viewport" content="width=device-width, initial-scale=1">  
  10.     <title>Token Based Authentication Example - Mukesh Kumar</title>  
  11.     <link href="App/Assests/Css/bootstrap.min.css" rel="stylesheet" />  
  12.     <link href="App/Assests/Css/sb-admin.css" rel="stylesheet" />   
  13. </head>  
  14. <body class="nav-md" ng-app="mukeshApp">  
  15.     <div ui-view></div>  
  16.     <script src="App/Assests/Js/jquery.min.js"></script>  
  17.     <script src="App/Assests/Js/bootstrap.min.js"></script>  
  18.     <script src="App/Assests/Js/angular.min.js"></script>  
  19.     <script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js"></script>  
  20.     <script src="App/Assests/Js/angular-ui-router.min.js"></script>  
  21.     <script src="App/app.js"></script>  
  22.     <script src="app/Components/Home/HomeCtrl.js"></script>  
  23.     <script src="app/Common/Services/EmployeeService.js"></script>   
  24.     <script src="App/Components/Login/LoginCtrl.js"></script>  
  25.     <script src="App/Common/Services/LoginService.js"></script>     
  26.     <script src="App/Common/Services/Factory/AuthInterceptor.js"></script>      
  27. </body>  
  28. </html>  

Now, it is time to run the application. Once you run the application, it will automatically redirect to the login page because token is not available right now. On the login page, you just need to provide the correct credentials and it will redirect to the home page.

Angular
Once you provide username and password and click the login button, it will redirect to the home page as following.

Angular

Conclusion

Today, we have seen how to implement Token Based Authentication in AngularJS application.

I hope this post helps you. Please put your feedback using comments, which will help me improve for the next post. If you have any doubts, please ask in the Comments section.