Implementing Two-factor Authentication like a Pro

Izabel Vasilyovska

In the following tutorial, we are going to cover what is Two-factor authentication, how the 2FA API works and how you can integrate it into your SashiDo app. We are certain that by the end of the article, you will be thrilled to take your application’s security to another level!

Introduction to Two-factor authentication

2FA is a security mechanism that adds an extra layer of protection to your online accounts, making them more secure than just relying on a password alone. It requires users to provide two different authentication factors before they can access their accounts, one of which is their password.

Nowadays, passwords are not a sufficient measure that guarantees 100% protection against malicious intents. A database breach, keylogger or a simple phishing email is sometimes enough to break a password and gain access to an account. Therefore it’s important to have this extra layer of protection.

How Two-factor authentication works

Whenever a user is logging into an account, usually they are required to use their username/email address and their password. As we have already deduced, it is not that hard to become a victim of a hacker’s attack, so it is crucial to have your credentials well protected.

This is where 2FA comes into play. In the unfortunate event when someone manages to access your users’ accounts, upon successful login, they will be prompted for a second verification - a one-time unique code will be generated and sent as an SMS to your user's mobile phone number. The code is only valid for a limited time window and if not added, it simply expires. Without the secret set of symbols, the user can’t complete the verification and no access will be granted which increases the safety of the account.

Implement Two-factor authentication into your app using Cloud Code.

If you are not familiar with implementing Cloud Code into your private GitHub repo, you can follow our Getting Started guide for a seamless setup.

Set up your Database and Twilio

First and foremost, to avoid database-related errors you have to complete a few steps:
1. Navigate to your SashiDo app’s Dashboard > Core > Browser > User. Select “Edit” from the top-right menu and click on “Add a new column”.
2. Create two database String fields called “phone_number” and “From” inside your User class.

create_class

Now that you have set up your database, you will need an SMS provider to send the authentication codes. We’ve chosen Twilio for the job. It is a cloud communications platform that allows software developers programmatically to make and receive phone calls, send and receive text messages, and perform other communication functions using web service APIs.

To get started, you just need to create an account in Twilio. As soon as your account is completed, you will be redirected to its Dashboard where you will find 3 keys that you need to implement into your Cloud Code: Auth Token*, Account SID* & Trial number*. Store the keys into a secure location. If you’d like to, you can store them as environment variables in your SashiDo app.

Add the code to your Cloud Code

Take a look at the code you need to implement. Firstly, you need to require the “crypto” module to generate random bytes from which a unique verification code will be created.

const crypto = require('crypto');

Afterwards, define the symbols that can be used to create the unique code.

const availableCharacters =
   'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

Now you need to add the Twilio verification codes that you got when you created your account.

const accountSid = process.env.TWILLIO_ACCOUNT_SID || 'Account SID';
const authToken = process.env.TWILLIO_AUTH_TOKEN || 'Auth Token';
const twillio = require('twilio')(accountSid, authToken);

const TWILLIO_FROM_NUMBER = process.env.TWILLIO_FROM_NUMBER || 'Trial Number';

Once you’re done with the above-mentioned steps, you can add the function that will generate a random 6-digit code. It does this by accumulating random bytes and mapping them to characters from a predefined set. The resulting code is returned as a string.

function generateCode() {
   const codeLength = 6;

   const bytes = crypto.randomBytes(codeLength);
   const code = new Array(codeLength);

   let cursor = 0;
   for (i = 0; i < bytes.length; i++) {
       cursor += bytes[i];
       code[i] = availableCharacters.charAt(
           cursor % availableCharacters.length
       );
   }

   return code.join('');
}

You can now create a cloud function named "login" that handles user login.

Parse.Cloud.define('login', async request => {
   const { username, password, code } = request.params;
   const user = await Parse.User.logIn(username, password);

Using a conditional statement, the following code checks if the user has a 6-digit authentication code and if they don’t have it, it will generate it for them.

if (!code) {
       const generatedCode = generateCode();
       user.set('code_2fa', generatedCode);
       await user.save(null, { useMasterKey: true });
       await twillio.messages.create({
           body: `Your 2FA code is ${generatedCode}`,
           from: TWILLIO_FROM_NUMBER,
           to: user.get('phone_number')
       });

The conditional statement then check if the generated code and the one that’s been entered by the user are the same. If they aren’t, it will throw an error and won’t allow the user to sign in.

} else if (code && user.get('code_2fa') !== code) {
       throw new Error('Invalid 2fa code');
   } else {
       user.unset('code_2fa');
       await user.save(null, { useMasterKey: true });
       return {
           sessionToken: user.getSessionToken()
       };
   }
});

The upload itself will trigger a build & deploy on your application. Once they are successfully completed it is time to actually test if everything works as it should.

To verify the process was a success you can create an API POST request calling the function. In this example, my username & password are both “123”. Then press “Send Query”.

Note: Make sure your user already has a phone number stored in “phone_number” in your database. Otherwise, you’ll get an error.

API-console-2

As soon as you execute the query, you will receive an SMS.
2fa-code

Now let’s give it a try inside a web browser for example. The front-end is connected to the code and the Submit button triggers the login function. The username & password are the same as the example above (123 & 123).

sashido-login

Once you click on the “Submit” button, the function is checking the username and password and if they are correct, a code is being generated to your phone as an SMS.

2fa-code-2

Now let’s get the code and type it into our 2fa code field.

code-field

There are 2 possible outcomes. If the code is correct, we will be granted access, if it is wrong we will be denied access.

result-popup

Conclusion

Two-Factor Authentication (2FA) is a crucial security measure that adds an extra layer of protection to online accounts. By requiring users to provide two different authentication factors, such as a password and a one-time verification code, 2FA significantly enhances account security. With the ever-increasing cyber threats, implementing 2FA has become essential to safeguarding sensitive data and preventing unauthorized access. Embracing 2FA helps users stay one step ahead of potential attackers and creates a safer digital environment for online interactions.

Izabel Vasilyovska

Customer Success Superstar @ SashiDo.

Find answers to all your questions

Our Frequently Asked Questions section is here to help.