Simple Two Factor Authentication Scheme

implementing multi-factor server-side authentication the easy way

Two factors too many

In a perfect world, we would not need any authentication. In a real world, we often feel protected enough by our Password1 universal password. Maintaining sufficient security is often a major pain for
internet organizations, as security and usability are almost always in either or relationship.

Unfortunately, oftentimes, the single authentication factor is not enough. As it happens almost on a daily basis, hackers might steal your social account password and post spam under your account.
Worse yet, somebody might gain access to your health record and make it public or steal your credit card information from your bank. Thus, most governments often require software businesses to be
compliant with multi-factor authentication schemes when it comes to securing sensitive information, such as electronic health records.

Two factor authentication systems can be composed of something a user knows and something a user has. Also, third authentication factor can be
something a user is, but, unfortunately, biometrics are beyond the scope of this post. For simplicity reasons, we will use client certificate as something a user has, and
username and password as something a user knows.

In this example, let’s assume we have an authentication server that provides access to web resources.

First Authentication Factor - SSL client certificate

One way to issue a client certificate from our certificate authority is by using the OpenSSL library and the steps below:

[root@linusaur certs]# openssl req -new -key testclient.pem -out
testclient.csr
Enter pass phrase for testclient.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code)[XX]:CA
State or Province Name (full name)[]:British Columbia
Locality Name (eg, city)[Default City]:Burnaby
Organization Name (eg, company)[Default Company Ltd]:Test Company
Organizational Unit Name (eg, section)[]:
Common Name (eg, your name or your servers hostname)[]:Test
Email Address []:yourname@gmail.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Now, we can give testclient.crt to a user which they will use as the first authentication factor. Every time the user tries to access a web resource on our server, our authentication server should
request this client certificate, check it against our certificate authority, and either grant or deny access.

Second authentication factor - username and password

Once a user passes the first authentication step, the server should then validate their username and password. Arguably, the simplest way for a user software to pass username and password to our web
service would be using HTTP protocol basic authentication scheme,
which uses base-64 encrypted username and password. For instance, user HTTP request header to our authentication server could look like this:

Where QkMwMDAwMEMzNTpTZXZDbGllbnRUZXN0 would be the output of a client-side function such as string base64encrypt(username + ":" + password).

Upon successful validation of username and password, our authentication server could issue a token which expires after a certain time, with which a client finally could access various resources.
Using the token we issued, the authenticated user resource request headers could look like this:

Both authentication factors working together

The system diagram demonstrates issuing tokens by a two factor authentication system, where usernames, passwords, and access tokens are stored in MySQL database. The authentication protocol flow is
described below: