Two-Factor Authentication (2FA) Using Speakeasy and Express.

Boro
The Startup
Published in
6 min readJan 21, 2021

Multi-factor authentication is an authentication method in which a user is granted access to a website or application only after successfully presenting two or more pieces of evidence to an authentication mechanism: knowledge, possession, and inherence.

In the same way, the two-factor authentication method requires you to enter additional data as evidence to access your account. The most common forms of two-factor authentication involve entering a code as used by Google and Facebook for additional security.

Advantages of Two Factor Authentication

  • Added layer security and added protection against cyber attacks.
  • Do not incur any extra costs while setting up.
  • Easy and convenient setup. For most implementations, all a user has to do is enable two-factor authentication and scan a QR code or enter their cellphone number so they can view or receive authentication codes respectively

NOTE: In this tutorial, we will deal with a backend that implements the time-based one-time password (OTP) made available to us by the Speakeasy library. This tutorial only covers the backend implementation of the two-factor authentication.

Setup

The very first step is to make sure you have appropriate versions of Node and npm installed. If not already you can follow the below links to download the absolute essentials as the very first thing we will be doing is run a Node server.

The next thing we do is create a project directory:

$ mkdir 2-fa
$ cd 2-fa

Now that we have our project folder, we will spin up a package.json using npm init:

$ npm init -y

After you go through a couple of ‘yes’ and customize the setup, you will have a package.json file that might look something like this:

{   "name": "2-fa",
"version": "1.0.0",
"description": "Two factor Authentication using Speakeasy",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "Sintu Boro",
"license": "ISC"
}

Run the following command to install the necessary dependencies:

$ yarn add express body-parser node-json-db uuid speakeasy ||
$ npm install express body-parser node-json-db uuid speakeasy
  • Express is a Node.js web application framework that we’ll use to spin our server.
  • The middleware body-parser package allows us to parse encoded data from incoming HTTP requests and expose them as req.body, so we can extract the essential data.
  • Node-json-db will be used as a database instance for storage.
  • Speakeasy is a one-time passcode generator, that we require for the two-factor authentication demonstration.

We now have all the necessary dependencies and are ready to create our server. In the project folder, create an index.js file that will act as an entry point to our project and add the following code to it:

At the root of your project, run the app to make sure everything is working alright:

$ node index.js

And now if we hit the route /api, we receive the following as a JSON response:

Generate Secret Key

We now need to generate a secret key that in turn generates us the two-factor authentication code through the Authenticator extension that we will be using. We will also have a route to register a user containing just the userID and the secret key generated by speakeasy.

To do this we will use Speakeasy’s generateSecret function. The response returns an object that has the secret in ASCII, hex, base32, and otpauth_url formats. We will only be using the base32 string to set up two-factor authentication. Paste the following code to create the register user route:

Right after we add the routes we can now make a POST request to this route to register a user like so:

Now open the Google Authenticator extension/app(this can be installed as an extension) and enter the secret key you just received like so:

Verify the secret

We now have the code generated to us through the secret key by the authenticator app. We now need to verify this code. Notice we have stored the secret as a temporary secret on the storage/database. Only after relevant validation, we can go ahead and store it permanently.

To perform the validation, we need to create another endpoint. The endpoint that verifies the code for us looks something like this:

Now open up the two-factor authentication extension and retrieve the code so we can verify the secret using a Postman request to the verify route.

After the validation, the secret key is now stored permanently and is used to verify future codes.

Verify User Tokens

The final step in the two-factor authentication is verifying the code that the user enters from their authenticator app. We need to add another route that will confirm that the tokens entered by the user are valid. The verification is handled by the Speakeasy TOTP(Time Based One Time Password) verify function.

This receives an object that contains the secret, the encoding to use to verify the token, the token, and a window option. A window refers to the period of time that a token is valid. This is usually 30 seconds but can vary depending on the time selected by the developer of the two-factor process.

You want to be careful to now pass out a large window allowance as that would lead to the verification process becoming less secure. Copy the code below to add the endpoint to validate the tokens.

Now hit the /validate route and verify the code from the authenticator using Postman.

And there you go! We have successfully implemented a two-factor authentication using Speakeasy. We looked into how we can register a user and create a secret shared between your server and the authenticator app; verifying the secret and using it to validate tokens.

The entire index.js file would look something like this:

index.js

References

Originally published at https://boro-blogs.netlify.app.

--

--

Boro
The Startup

I write about web design, front-end technologies, development and best practices at large.