Welcome to Innominds Blog
Enjoy our insights and engage with us!

Client Side Authentication Using AngularJS

By Yazna Kumar Vemuri,

Authentication plays an important role in today's web applications. It is a process of accessing application or features by providing user’s identity that helps the verifier in getting complete information about the user’s activity. We can categorize the web-applications into 2 types – Public & Private.

Public Sites: User can access the information available in the domain without providing any credentials. The information is open to public and is not restricted to any set of users/groups.

Private or Restricted Access: Information available in the sites/domain will be made available only when the user supplies proper credentials and the same is validated by the server. Ex: Gmail, Facebook etc.

The common techniques used in Angular for authentication are "Basic" and "Bearer" and they are described further in detail.

 

Basic Authentication

Basic authentication is one of the simplest authentication techniques wherein browser sends HTTP requests with the authorization header that contains the property ‘Basic.’

Basic authentication follows the ‘Base64-encoded’ concept.

Example: If we have a username “test” and a password as “test123”.

Username and password concatenated with “:” - “test:test123

Base64 applied on the concatenated string - BgXtbzpwQDU2dzByZA==

Browser will send this code by adding it to the authorization http header

Authorization: Basic BgXtbzpwQDU2dzByZA==

4. When the server receives this request, authorization headers are read and decoded. The decoded username and password are validated and if the validation succeeds, the response is sent back to the client. In case the validation fails, an error status is sent.

The username/password string is sent with each service call to the server. Steps 1-4 are repeated for every service call.
Note: Base64 is easily encodable and it should be implemented with the help of HTTPS/SSL.

 

Example:

HTML code:

<input type="text" name="username" ng-model="username" required/>

<input type="password" name="password" ng-model="password" required/>

<button type="button" ng-click=”login()”>Login</button>

Login Controller:

'use strict';

angular.module('Authentication').

controller('LoginController', ['$scope', '$location','AuthService',

function($scope, $location, $authService) {

$authService.ClearCredentials();

$scope.login = function() {

$authService.Login($scope.username, $scope.password, function(response) {

if (response.success) {

$authService.SetCredentials($scope.username, $scope.password);

$location.path('/');

} else {

$scope.error = response.message;

}

});

};

}]);

If the response from the server is successful, the user will be redirected to the home page of the application. In order to send username and password for consecutive service calls, we should set base 64 encoded values to 'Authorization' header (as shown below). But if the response from server comes out as an error, we show an error message to user without directing the user from login page.

AngularJS Authentication Service


'use strict';
angular.module('Authentication')
.factory ('AutheService',

['Base64', '$http', '$cookieStore', '$rootScope', '$timeout',

function (Base64, $http, $cookieStore, $rootScope, $timeout) {
var service = {};


service.Login = function (username, password, callback) {
$http.post('/api/authenticate', { username: username, password: password })
.success(function (response) {
callback(response);
});
};

service.SetCredentials = function (username, password) {
var authdata = 'Basic ' + Base64.encode(username + ':' + password);


$rootScope.globals = {
currentUser: {
username: username,
authdata: authdata
}
};

$http.defaults.headers.common['Authorization'] = authdata;

$cookieStore.put('globals', $rootScope.globals);
};

service.ClearCredentials = function () {
$rootScope.globals = {};
$cookieStore.remove('globals');
$http.defaults.headers.common.Authorization = 'Basic ';
};
return service;
}]);

 

Angular Token-Based Authentication

Token-based authentication has been widely used due to its RESTful web APIs and SPA among others.

Token-Based Authentication Flow:

User enters their login credentials and the server verifies the credentials. Server then validates the entered credentials irrespective of it being correct or incorrect. If the credentials are correct, it returns a signed token. This token is stored on the local storage at the client side. We can also store the token in session storage or in cookies.

Code Snippet:

private _setSession(authResult, profile) {

localStorage.setItem('access_token', authResult.accessToken);

localStorage.setItem('id_token', authResult.idToken);

localStorage.setItem('userProfile', JSON.stringify(profile));

this.setLoggedIn(true);

}

 

Advantages of Token-Based Authentication:

1. Stateless

2. Scalable

3. Decoupled

4. JWT (Jason Web token) is placed in the browsers local storage

5. Protect Cross Domain and CORS

6. Stores Data in the JWT

7. XSS and XSRF Protection

 

JSON Web Token (JWT):

JSON Web Token (JWT) is an open standard (RFC 7519) token that defines a compact & self-contained way for securely transmitting information between parties as a JSON object. This information can be verified & trusted because it is digitally signed. JWTs can be signed using a secret (with the HMCA algorithm) or a public/private key pair using RSA. In other words, Token (JWT) is a compact ‘URL-safe’ means of representing claims to be transferred between two parties.

JWT Token Format:

JSON Web Tokens consist of three parts separated by dots (.) and they are as follows:

Header

Payload

Signature

Therefore, a JWT token looks like xxxx.yyyy.zzzz

Header:

The header typically consists of two parts:

The ‘type’of the token, which is JWT and

The hashing algorithm being used, such as HMAC SHA256 or RSA

Example:

{

"alg": "HS256",

"typ": "JWT"

}

Then, this JSON is Base64Url encoded to form the first part of the JWT.

 

Payload:

The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically the user) and additional metadata. There are three types of claims: Registered, Public and Private claims.

Registered claims: Contains information about: 'iss' (issuer), 'exp' (expiration time), sub (subject), aud (audience) and others. These claims are optional but are recommended.

Public claims: These can be defined at will by those using JWTs. But to avoid collisions, they should be defined in the IANA JSON Web Token Registry or be defined as a URI that contains a collision resistant namespace.

Private claims: These are the custom claims created to share information between parties that agree on using them and are neither registered nor public claims.

Example:

{

"sub": "1234567890",

"name": "John Doe",

"admin": true

}

 

The payload is then Base64Url encoded to form the second part of the JSON Web Token.

Signature:

To create the signature part, you must take - the encoded header, the encoded payload, a secret, the algorithm specified in the header and sign in.

Example (using HMAC SHA256):

HMACSHA256 (

base64UrlEncode(header) + "." +

base64UrlEncode(payload),

secret)

 

Signature is used to verify the sender and ensure that the message has not been changed during transmission. Combining all three results in the following token (HEADER, PAYLOAD, SIGNATURE)

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5ODc0NTYzMjEwIiwibmFtZSI6IkF2aW5hc2ggQmF0aGluaSIsImFkbWluIjp0cnVlfQ.qadS9qTPLG9kOGW852OrpfJWaZtaAL7IYqr_cnHsjX8

 

Now using Angular, we’re going to create an AUTH Service and mark it as @Injectable(). This is done to inject dependency wherever required:

import { Injectable } from '@angular/core';
declare var Auth0Lock: any;

@Injectable()
export class AuthService {

lock = new Auth0Lock('YOUR_AUTH0_CLIENT_ID', 'MY_AUTH0_DOMAIN');

login() {

this.lock.show((err: string, profile: Object, id_token: string) => {

localStorage.setItem('profile',JSON.stringify(profile));

localStorage.setItem('id_token', id_token);

});

}

logout() {
localStorage.removeItem('profile');
localStorage.removeItem('id_token');
}

}

We have successfully created Auth service with code above. Let's create a component and inject it.

import { AuthService } from '../services/auth.service';

@Component ({
selector: 'YOUR_COMPONENT_NAME_HERE',
template: `
<div>
<button (click)="auth.login()">Login</button>
<button (click)="auth.logout()">Logout</button>
</div>
`,
providers:[AuthService]
})


export class YOUR_COMPONENT_NAME_HERE {
constructor(private auth: AuthService) {}
login(){
this.auth.login();
}
logout(){
this.auth.logout();
}
}

Once the user logs into JWT and user profile data are saved in local storage, we can successfully inject our Auth service. When we call any rest service, JWT should be attached to the header and sent. This can be done automatically using Auth0’s angular2-jwt module.

We can inject "AuthHTTP" module wherever we need to and use it to send authenticated requests. For instance, we have a component that fetches a list of users from a backend and displays them. We can import AuthHttp from angular2-jwt and subscribe it with Rx:


import { AuthHttp } from 'angular2-jwt';
import 'rxjs/add/operator/map';

interface User {
id: number,
name: string,
image: string
}

@Component({
selector: 'user-list',
template: `
<h2>Users</h2>
<ul>
<li *ngFor="user of users">
<img [src]="user.image">
<span></span>
</li>
</ul>
`
})
export class UserListComponent implements OnInit {
users: User[];
constructor(private authHttp: AuthHttp) {}
ngOnInit() {
this.authHttp.get('/my-app.com/api/users')
.map(res => res.json())
.subscribe(
users => this.users = users,
error => console.log(error)
);
}
}

When we use AuthHttp instead of the regular Http module shipped with Angular, the JWT in local storage gets attached as an Authorization header. We could write some logic to create headers and then attach them to each regular Http request manually, but angular2-jwt does this for us.

 

Conclusion:

We have seen both "Basic" & "Bearer" authentication techniques in detail. Depending upon the requirement, we can use either of these techniques in our application. While using "Basic" authentication, one needs to be cautious about sending user credentials for each service call. The credentials should be encrypted with SHA256 or with a similar cryptographic function with some secret key before it gets transmitted over the service call making it easy for an attacker who wishes to crack user credentials.

 

Innominds is a trusted innovation acceleration partner focused on designing, developing and delivering technology solution in specialized practices in Big Data & Analytics, Connected Devices, and Security, helping enterprises with their digital transformation initiatives. We build these digital practices on top of our foundational services of UX/UI, application development and testing for technology companies. From ideas to commercialization, Innominds provides great ideas, engineering talent and proven technology solutions that help our clients succeed in today’s highly competitive market.

Interested! For any demos or POCs, please write to us at marketing@innominds.com and know more about our offerings.

Topics: Design UX & UI

Yazna Kumar Vemuri

Yazna Kumar Vemuri

UI Technical Lead at Innominds

Explore the Future of Customer Support with Latest AI! Catch up on our GEN AI webinar held on June 25th at 1:00 PM EST.

Authors

Show More

Recent Posts