How to authenticate an HTTP request

Have you ever wondered what happens after you log in to a website? You may think it is like opening a drawer of your own using your key and then having access to everything inside. But this is not a proper metaphor. Whenever you request a resource from the website, you actually sends a HTTP request to the server through your browser. HTTP is a stateless protocol, meaning that

  • each request/response happens in isolation
  • each request is not aware of the state of the communication

Thus, a server cannot tell if an HTTP request comes from an authenticated user unless you provide your user name and password in each request, or the server and/or the client keeps track of the state of the communication. Of course, it is silly to ask the user for password every time when a request requires authentication, so it leaves us with the second option.

This post is about how to keep track of the state of the communication between the client and server, and it covers two solutions.

Solution I: session management

A web session is a sequence of HTTP request and response transactions associated to the same user.

Session management is a solution that the state of communication is maintained on the server side.
When a client starts a communication with a server, the server will create a key/value pair - generating a session ID as the key and using information relating to the current session (such as user name and user state) as the value, and maintain it on the server side. The server then sends back the session ID. Next time the client sends requests to the server, the requests will bring the session ID with them (if the session hasn’t been expired), so the server can identify where the requests come from. If the user logs in to a website, the server will update the user state as authenticated.
The session expires due to timeout or user’s logout. When it expires, the session ID becomes invalid and the session data is deleted, and hence the server cannot identify the following requests.

Cookie-based and URL rewriting are two mostly adopted implementation of session management.

Cookie-based session management
The session ID is stored in the cookie by the server using the HTTP header Set-cookie. When the client sends a request to the server, the browser will send the cookie along with the request - but this is not always true, of course, due to the security attributes on cookies, but let’s put it aside for now.

URL rewriting
The browser stores the session ID in its local memory and attaches it to the request URL like this https://xxxxxx;sessionid=xxx.

Cookie-based vs. URL rewriting:

Cookie-based URL rewriting
Cannot be used if cookie has been disabled by the browser No limitations
No extra implementation required for the client The client must implement URL rewriting for each request

Apart from above, cookie-based is a preferable choice from the security perspective. For one reason, we can use the security attributes to limit the usage of cookie for session ID. For another reason,it is much easier to modify the URL than to modify the cookie for accessing your resources, suppose your active session ID is stolen.

Until now, what I have discussed is based on the assumption that a client deals with only one server, so the session data can be stored in the local memory; in other words, the session data is not shared among the servers.

Quick question: how can the HTTP requests of one client go to the same server?
This can be achived by putting an HTTP load balancer in front of servers and configuring ip-hash load balancing (or having other session persistence configuration enabled).

It is a simple solution, but it does not take into consideration the weights assigned to the servers. The servers which most of the traffic goes to might become the bottleneck. This solution cannot be applied in the case where a single node might be overloaded.

If ip-hash load balancing cannot be used, then we have to make the servers share the session data. We can introduce a storage system for storing the data and the data can be accessed by all the servers. Here is an open-source solution: memcached-session-manager.

Solution II: token maintained on the client side

This solution requires the token to be stored in local storage on the client side, and the server side needn’t maintain the user state.

It works in this way:

  1. For authentication, the client provides user name and password to a server.
  2. If the user is authenticated, the server generates a token and sends it back to the client.
  3. The client stores the token in the local storage or cookie.
  4. The client sends HTTP requests along with the token to any server.
  5. The server which receives the request will verify the validation of the token (including whether the token has expired or not); if it is valid, it will respond with the data that the client asks for.

The cons of this solution are obvious: the server has to valid the token for each request. But it has its pros:

  • No need to manage session on the server side, meaning no worry about load balancing and high traffic volumn
  • No limitation on crossing different domains
  • Naturally suitable for Single Sign-On (I’ll talk about this later)

The challenge of this solution is how to decign the token. I would recommend JSON Web Tokens instead of building your own wheel.

More: single sign-on

Single sign-on (SSO) is a property of access control of multiple related, yet independent, software systems. With this property, a user logs in with single ID and password to gain access to a connected system or systems without using different usernames or passwords, or in some configurations seamlessly sign on at each system.

One way to implement SSO is to use token which can be interpreted by different application systems.

An alternative way is to introduce a central management system. All the application systems must communicate with the central management system for authentication. An example is CAS.

References

1 Http: The Definitive Guide
2 Wikipedia: Stateless Protocol
3 Wikipedia: Single sign-on