Back to basics: HTTP Basic Authentication

An area of software development I have found a great interest in, is that of the full stack of web development. In my day job this has seen me doing quite a bit of digging into the Microsoft stacks of ASP.NET MVC and Web Api - my after hours development has focused on Node.js based tools.

A great deal of efforts have gone into the major frameworks in abstracting details of underlying web technologies, including that of security. However, I feel it is important to understand, at least to some extent, how the underlying technologies work in order to make the right decisions on which features to implement and insuring that they are implemented correctly. Knowing what to expect is also of great help during troubleshooting exercises.

In this post I want to give a brief, but practical rundown of HTTP Basic Authentication, which is explained in full in RFC 2617 (no, I didn't read it either). Personally I understand things better when provided with a concrete example, so I will attempt to explain it in as much practical terms as possible.

On a high level, Basic Authentication works on the following set of steps, which will be explained in more detail later:

  1. A client makes an initial HTTP request to a server and does not provide any authentication data.
  2. The server provides a response, indicating that the client is not authorized. Along with the response it also provides a challenge indicating what kind of authentication mechanism it implements.
  3. The client then sends its credentials on the following HTTP request.
  4. The server authenticates the client credentials and sends back a response containing the requested resource, if authentication succeeds.

To explain these steps in more practical terms, I will make use of a very simple web server that I have implemented using Node.js. This server makes use of the node module basic-auth to parse the Authorization request header and to extract the client credentials.

Step 1. A client makes an initial HTTP request to a server and does not provide any authentication data.

Once the web server has been started, this step can be simulated using Fiddler (or any other HTTP client) and sending the following HTTP request message:

GET http://localhost:3000/ HTTP/1.1
User-Agent: Fiddler
Host: localhost:3000

Step 2. The server provides a response, indicating that the client is not authorized. Along with the response it also provides a challenge indicating what kind of authentication mechanism it implements.

The following HTTP response is received from the server:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="SecureDocuments"
Date: Wed, 16 Nov 2016 19:30:52 GMT
Connection: keep-alive
Content-Length: 13

Access denied

As seen above, the server responds with an HTTP 401 (Unauthorized) response code and provides the challenge in the WWW-Authenticate response header, indicating that the Basic response mechanism is used and applies to the realm "SecureDocuments" (I have yet to investigate what the realm represents and what its application is).

Step 3. The client then sends its credentials on the following HTTP request.

The client then sends another request to the server, whereby the it provides its authentication credentials in the request Authorization header:

GET http://localhost:3000/ HTTP/1.1
User-Agent: Fiddler
Host: localhost:3000
Authorization: Basic cmlhYW5kcDokdXBlciRlY3JldA==

The content of the Authorization header is very easy to construct (and deconstruct). It consists of the "Basic" keyword followed by a base64 encoded representation of the colon-combined client user name and password values. For this example, looking at the web server code it can be seen that it expects a client name of riaandp and password $uper$ecret. Combining these values into the token riaandp:$uper$ecret and encoding it to a base64 representation results in the value cmlhYW5kcDokdXBlciRlY3JldA==.

Step 4. The server authenticates the client credentials and sends back a response containing the requested resource, if authentication succeeds.

Since the correct credentials were supplied, the server responds with the following data:

HTTP/1.1 200 OK
Date: Wed, 16 Nov 2016 19:41:31 GMT
Connection: keep-alive
Content-Length: 14

Access granted

If the credentials were not correct, the server would respond with the same response as in Step 2.

The are a lot of information online regarding the pros and cons of using this mechanism, so I will not cover these within this post. One crucial consideration I will however highlight is to use this mechanism only when a secured transport layer such as TLS is enabled on the connection. This is very important as the credentials are not encrypted and as such is vulnerable to a man-in-the-middle attack if not secured appropriately.