Recently I was working on yet another startup project (mobile app with backend). The goal was to make the backend stateless and highly scalable. I did not want to maintain sessions. So I was looking for authentication and authorization mechanism for RESTful APIs which is scalable, secure and appropriate for mobile. The solution was HMAC. This post describes how to handle it using spray.io.
The main constraint of REST web APIs is stateless client-server communication. The client is required to provide all the information necessary to handle the request. The most simple way to handle the authentication and authorization in RESTful APIs is HTTP basic authentication. In this approach, username and password are provided as a header. Thus, this method is insecure. Hash-based message authentication code (HMAC) provides more secure mechanism by usage of a hash-based code instead of password.
In HMAC, authentication based on user identifier and hash code which is calculated and attached to each request. The HTTP method, URL and abridged timestamp are combined and hashed using user’s secret. The user’s secret is stored on client and server side. The server builds own hash using the same variables and compare it with given one. See RFC 2104 for more details.
The library provides a directive for HMAC authentication. The user is required to extend Authentication trait and implement accountAndSecret method, which is supposed to return tuple of account and account’s secret for given account identifier.
In addition to the library, I shared also sample client implementation for AngularJS spray-hmac-angularjs-example. The factory HMAC is used to build the hash based on secret, method, path and time.
The $httpProvider interceptor can be used to automatically inject HMAC header for each requests.
HMAC provides simple and scalable alternative for session based authentication and authorization. It is especially useful for mobile applications which call RESTful APIs and do not rely on OAuth2. The user’s secret can be stored on a device when a user logs in, and removed when user logs out. It can be easily integrated with device management.