Securing a JavaScript Single Page App with RESTful backend

The service offered by the token is that the server will somehow recognize the token as one of its own. How can the server validate a HMAC-based token ? By recomputing it, using its secret HAMC key and the data over which HMAC operates. If you want your token to be computed over the userID, password, IP and date, then the server must know all that information. However, you do not want your server to store the password, and the client will not send it back with each request. How can your system work, then ?

The basic idea, however, is sound:

  • Users "logs in" by any way which you see fit.
  • Upon such login, the server sends a cookie value, to be sent back with each subsequent request (that's what cookies do).
  • The cookie contains the user ID, the date it was issued, and a value m = HMAC(K, userID || date || IP).
  • When the server receives a request, it validates the cookie: the userID and date are from the cookie itself, the source IP is obtained from the Web server layer, and the server can recompute the value m to check that it matches the one stored in the cookie.

You could replace the whole cookie with a random session ID, if the server has some (temporary) storage space. Indeed, the server could remember the mapping from a random session ID to the user-specific information (such as his name and IP address); old session ID can be automatically expired, so the storage space does not grow indefinitely. The cookie described above is just a way to offload storage on the client itself.

Note: using the IP address may imply some practical issues. Some clients are behind proxies, even load-balanced proxies, so not only is the client IP address possibly "hidden" (from the server, you see the proxy's address, not the client's address) but the IP address you obtain server-side could move around erratically (if two successive requests from the client have gone through distinct proxies in a proxy farm).


There is a much simpler solution:

Use SSL sitewide, and then use your framework's standard session tracking.

That's all you need to do.

In more detail, the user initially logs in by supplying their username and password; it gets POSTed to the server, who can check its validity. If the authentication is successful, your server code sets a flag in the session state remembering that the user has successfully authenticated and remembering the user's username. All subsequent requests will be over the same session, so you can easily authenticate them and allow them to proceed.

(Still more detail: Each time you receive a request, you check the session state to see whether the user has successfully authenticated and is authorized to perform this action. If yes, you allow the request and perform the action; if no, you redirect the user to a login page or present some other error message.)

Notice that this meets all of your requirements. It does not require a database lookup on each request. It is compatible with a RESTful API. It is compatible with a single-page app. You don't need to code up anything fancy: you just use your framework's existing support for sessions (usually, it uses a session cookie with a unique session ID, and some mechanism to store state on the server side associated with that session ID).

As part of using SSL sitewide, you should set the secure flag on your session ID cookie, to protect it from eavesdropping (this will ensure it will never be sent over HTTP). You should also enable HSTS, to tell the browser to always use SSL on your site. Search this site for more information on how to deploy SSL sitewide.

You should not rely upon the client's IP address to be static. It may change, e.g., if the client is mobile and moves from one wireless network to another. Therefore, it is best to avoid using the client's IP address for anything.


Check this post Using OAuth2 in HTML5 Web App. @jandersen answer gives a good explanation on using Resource owner password credentials flow in single page applications. In any case, the prefered flow for this apps should be the Implicit grant. In fact, @jandersen 's response on the referenced post is about tweaking Resource owner password credentials to act as something close to the Implicit grant.