Token-based authentication for AngularJS Application

Token-based authentication for AngularJS Application

Because AngularJS is client-side implementation, we have different authentication strategies, for example, we can use cookie-based, just like normal website, or we can use token-based, just like mobile apps with web-service. Both way can work seamlessly without any problem and have their own pros and cons. We should consider using token-based when we need to:

  • Cross-domain / CORS: cookies + CORS don’t play well across different domains. A token-based approach allows you to make AJAX calls to any server, on any domain because you use an HTTP header to transmit the user information.
  • Stateless (a.k.a. Server side scalability): there is no need to keep a session store, the token is a self-contanined entity that conveys all the user information. The rest of the state lives in cookies or local storage on the client side.
  • CDN: you can serve all the assets of your app from a CDN (e.g. javascript, HTML, images, etc.), and your server side is just the API.
  • Decoupling: you are not tied to a particular authentication scheme. The token might be generated anywhere, hence your API can be called from anywhere with a single way of authenticating those calls.
  • Mobile ready: when you start working on a native platform (iOS, Android, Windows 8, etc.) cookies are not ideal when consuming a secure API (you have to deal with cookie containers). Adopting a token-based approach simplifies this a lot.
  • CSRF: since you are not relying on cookies, you don’t need to protect against cross site requests (e.g. it would not be possible to <iframe> your site, generate a POST request and re-use the existing authentication cookie because there will be none).
  • Performance: we are not presenting any hard perf benchmarks here, but a network roundtrip (e.g. finding a session on database) is likely to take more time than calculating an HMACSHA256 to validate a token and parsing its contents.
  • Login page is not an special case: If you are using Protractor to write your functional tests, you don’t need to handle any special case for login.
  • Standard-based: your API could accepts a standard JSON Web Token (JWT). This is a standard and there are multiple backend libraries (.NET, Ruby, Java,Python, PHP) and companies backing their infrastructure (e.g. Firebase,Google, Microsoft). As an example, Firebase allows their customers to use any authentication mechanism, as long as you generate a JWT with certain pre-defined properties, and signed with the shared secret to call their API.

Authentication for AngularJS with Token

The most simple case of implementing token-based app is as follow:

  1. Client app performs request to server-side with authentication info, for example: username and password. Server-side then calculate hash check and if info is valid, server returns client a token string, which represent user validity. This token is generated at server-side when user first login/signup and stored in user table.
  2. Client app will store token using cookie or local storage, then intercept the token onto every AJAX requests.
  3. When user choose to logout, clear saved token.

This implementation has some issues need to be resolved:

  • If the token has been stolen, then attacker can use the token to perform request anytime, anywhere.
  • Token is not encrypted in both local and server-side, which can lead to vulnerable risk.
  • Token is first created when user sign up and not like password, token can’t be changed.

We can change the flow a little bit:

  1. At server-side, every token will have expire time, for example, 1 hour or 1 day. We need a separate token table, which has foreign key to user id.
  2. The expired token will lead to invalid access information, therefore if token is stolen, it will be invalid soon and can not be used to perform attack and/or steal information from REST service.
  3. At user logout, before clear token, we can send a request to server to ask for removing or disable unused token.

This flow leads to another problem: inside web environment, user can be asked for logging in when token expired, but if we are inside mobile app, user should not be asked to login again. Then we want to have a strategy which automatically renew expired token. We can define token state as follow:

  • state 0: token has not been expired, can be used for request
  • state 1: token has been expired, and will be used for renewal, but can not be used for request
  • state 2: token has been used for renewal, and thus is disabled, or can be safely removed from token table

It seems to be OK now, we will solve last issue about encryption. You may want to encrypt all data or just encrypt only authorization part. In my opinion, ecrypt only authorization is enough. This is how Vuforia implement their encryption request part:

Authorization: VWS {provision_access_key}:{Signature}

Which Signature field is calculated as follow:

Signature = Base64(HMAC-SHA1(server_secret_key, StringToSign ) ) ; StringToSign = HTTP-Verb + "\n" + Content-MD5 + "\n" + Content-Type + "\n" + Date + "\n" + Request-Path;

Thefore, all requests will have different signature, and can not be reused, although attacker can reverse engineering onto data of request, they are unable to perform same request again. Of course, Vuforia offers per-app secret/access key, while we don’t need to create secret/access key for every single client, we will use a predefined key for encryption. And that was enough.

In a more few day, we will have a case study about how we implement in product-ready mobile-first app with CMS for administrator is written in AngularJS. Stay tuned!.