One of the simplest and most diffused tools to authenticate operations between clients (e.g. a browser) and servers (e.g. a back-end) is Basic Access Authentication.

To implement Basic Auth in your client/server calls, you need to add on client side a header for any call (GET, POST...) containing the string Base64 “Authorization:Basic username:password”.

Is it safe?

Let's clarify a point immediately. Basic Auth is a safe protocol, widely diffused and used. The fact that username and password are passed on in plain text, with no encryption, does not affect the protocol security. Of course you need to foresee in advance an added encryption layer. For this purpose, the easiest way to proceed is to setup an HTTPS connection between client and server, to prevent the reading of credentials passed at each call. So if you want to use Basic Auth, use it on HTTPS connections.

How to setup the Base64 header

Base64 is a numbering system using 64 different symbols, based upon a very simple encoding/decoding algorithm. It does not provide an irreversible hash table (unlike md5 or sha1). Javascript does not provide a native base64 function (unlike e.g. PHP). Nonetheless, it can be easily implemented using the following functions:

var _base64 = {
		_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
		encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=_base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},
		decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9+/=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=_base64._utf8_decode(t);return t},
		_utf8_encode:function(e){e=e.replace(/rn/g,"n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},
		_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}
	}

Basic Auth in AngularJS

Making use of the above mentioned functions, you can calculate the hash needed for your calls. The most used tool to interrogate remote services is $http, available in the native package of AngularJS. If you need to query via $http an endpoint protected with authentication, you have simply to setup the proper headers for your calls.

$http.defaults.headers.common.Authorization = "Basic " +_base64.encode(username + ":" + password);

$http allows the definition of some global scope headers (that is, such headers will be used by all next calls). Basic Auth is often activated only after a successful Login operation (after a successful Login, the application starts signing the requests with the proper headers): so the best way to proceed is the definition of a service capable to manage login/logout operations:

angular.module('myApp', [])
.factory('myAuth', ['$http', function($http) { 
	
	var myAuth = {};
    
    var myAuth._base64 = {
		_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
		encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=_base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},
		decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9+/=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=_base64._utf8_decode(t);return t},
		_utf8_encode:function(e){e=e.replace(/rn/g,"n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},
		_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}
	}
    
    
    /**
     * sign the request.
     */
    myAuth.login = function(username, password) {
           
        if(username && password) {
        	$http.defaults.headers.common.Authorization = "Basic " + myAuth._base64.encode(username + ":" + password);
        } 
    };
    
    /**
     * delete the auth header
     */
    myAuth.logout = function() {
        delete $http.defaults.headers.common['Authorization'];
    };
     
    return myAuth;
}]);

Gabriele Mittica

Developer at Corley S.r.l , Website , Git home page , @gabrielemittica , Linkedin profile
Passionate startupper, Cloud developer and amstaff lover. Worldwide geekka traveler!

All articles by Gabriele Mittica

Comments

comments powered by Disqus

cloudparty

Follow Us