Sunday 4 August 2013

AngularJS and ExpressJS Basic Auth

So I have successfully implement the Basic Authentication method with AngularJS as frontend , and using ExpressJS as my REST service provider.

Lets dig in the specification first which are :

  1. The client will have to sent the Basic authentication header in every XHR request
  2. The XHR request will be using the factory $resource in AngularJS
  3. The REST service will need to check the Authentication header in every request
  4. If no authentication header available, it will response with 401 code
  5. If the authentication header available, check against user database, if not match response with 401 code
  6. If credential match, continue with next operation
  7. The check will be implemented as a middleware to every request
 First, here are the angular code :

Here are the factory User in services/user.js :

'use strict';

angular.module('userServices', ['ngResource'])
  .factory('User', ['$resource','globalData',function ($resource,globalData) {
    // Service logic
    // ...
    // Public API here
    var url = globalData.getApiBaseUrl();
    return $resource(url + '/user/:id/',{id: '@_id'},
      {update: {method:'PUT'}

      }
    );
  }]);

Here are the globalServices, in services/globalData.js

angular.module('globalServices', [])
  .factory('globalData',['$cookieStore','$http', function ($cookieStore,$http) {
   getAuthToken: function () {
        var auth = window.btoa(this.getUser()+':'+this.getApikey()); //inject the user and password/apikey here
        $http.defaults.headers.common['Authorization'] = 'basic '+auth;
        return ;
      },

}]);


And in every controller you have call the method to inject the header. here are UserCtrl in controllers/user.js :

angular.module('myapp')

 .controller('UserCtrl',['globalData','User', function (globalData,User){

      var q = globalData.getAuthToken();

      $scope.user = User.query(q);
}


With this, everytime angular request data to REST server, there will be authentication header which you will get from login before or you have it in your config.

And now in the server , we process the request header in every request which we want to authenticate before processing.

In express, we use module for code organization, and we put it in authapi.js module :

var User = require('../models/users');

module.exports = {
  checkApiAuth: [
    /* This work as middleware , before all controller run this will run
     * will check the user & api query param to db
     * if they are correct, will be found in db
     * if not found, will send 401 / unauthorized
     * since 9 June 2013
     */
    function (req, res, next){
      var header=req.headers['authorization']||'',        // get the header
       token=header.split(/\s+/).pop()||'',            // and the encoded auth token
       auth=new Buffer(token, 'base64').toString(),    // convert from base64
       parts=auth.split(/:/),                          // split on colon
       username=parts[0],
       apikey=parts[1];
       console.log('headers :'+header+' : '+ username+':'+apikey);
       if (!username || !apikey){
        res.send(400);
      }
      else{
         //process to check the database info

            if (apikey === db.apikey){
              return next(); //here we will process next function called in routes module
            }else{
              res.send(401);
            }
      }
  }]
} 


And to use it in every request, add it in router module of your expressjs application.
Here are ./routes/user.js

/*
 * User Routes
 */

var userCtrl = require('../controllers/users');

module.exports = function(app, apiAuth ){
    //API exposed
    app.get('/api/user', apiAuth.checkApiAuth, userCtrl.getList);
    app.post('/api/user',  userCtrl.createWApi);
    app.put('/api/user/:id',apiAuth.checkApiAuth, userCtrl.update);
    app.get('/api/user/:id', apiAuth.checkApiAuth, userCtrl.read);
    app.delete('/api/user/:id', userCtrl.delete);
}


And in the app.js for expressJS initialization add :

  var apiAuth = require('./lib/authapi');

  require('./routes/user')(app,apiAuth);

0 comments:

Post a Comment

Twitter Delicious Facebook Digg Stumbleupon Favorites More