Thursday, March 06, 2014

Simple access_token Pattern in Angular JS

In a recent work I did I had to solve the problem of automatic insertion of Authorization header in all subsequent requests to a REST service after authenticating with it. Here is a simple solution I came up with:

(function(){
angular.module('RestClient', [])
.constant('authmap', {})
.config(function($httpProvider) {
    $httpProvider.interceptors.push(function($q, authmap) {
        return {
            'request' : function(config) {
                // Is this http[s] URL
                if (/^http[s]?:\/\//i.test(config.url)) {
                    // Check authmap if it has key that is prefix of config.url
                    var access_token;
                    for (var key in authmap){
                        // Is key a prefix?
                        if (config.url.indexOf(key) === 0) {
                            access_token = authmap[key];
                            break; // Found access token so break
                        }
                    };
                    if (!!access_token) {
                        // Yes, inject Authorization header
                        config.headers.Authorization = 'Bearer ' + access_token;
                    }}
                }
                return config;
            }
        };
    });
})
.factory('AuthenticationService', function($http, authmap) {
    return {
        login : function(target, email, password) {
           var authentication = ...; // Authenticate and get access_token
            // Record access_token for target
            // This will be used by the interceptor to
            // supply Authorization header
            authmap[target] = authentication.access_token;

        },
        isLoggedIn: function(target){
            return !!(authmap[target]);
        },
        logout : function(target) {
            if (!!target) {
                if (this.isLoggedIn(target)) {
                    // Forget access_token for target
                    delete authmap[target];
                }
            }
        }
    };
});
})();

IMHO this approach is better than the approach described here where one globally sets the $http.defaults.headers.common.Authorization header, because that affects all requests.

This was written for angular 1.2+.

The code does not show how you authenticate. It assumes that you got back a authentication object with property access_token in it.

I hope folks find it useful.

No comments: