Two-Factor Authentication Using Node.js

    Two-factor authentication (2FA) can play a key role in securing your applications against password data breaches. Authentication with a one-time password (OTP) delivered to your users over SMS is an effective approach to implementing two-factor authentication. Plivo’s premium direct routes guarantee the highest possible delivery rates and the shortest possible delivery times for your 2FA SMS messages.

    This guide shows how to set up SMS-based two-factor authentication using either PHLO or traditional API development. PHLO lets you create and deploy workflows from an intuitive graphical canvas in few clicks.

    You can create and deploy a PHLO to handle 2FA with a few clicks on the PHLO canvas and trigger it with a few lines of code.

    Prerequisites

    To get started, you need a Plivo account — sign up with your work email address if you don’t have one already. If this is your first time triggering a PHLO with Node.js, follow our instructions to set up a Node.js development environment.

    Create the PHLO

    Plivo provides a prototype for 2FA; all you have to do is select the PHLO and give it a friendly name.

    PHLO Setup

    Set up the demo application locally

    Once you‘ve created the PHLO, download and modify the code to trigger it.

    • Clone the repository from GitHub.
     $ git clone https://github.com/plivo/2fa-node-demo.git
    • Change your working directory to 2fa-node-demo.
     $ cd 2fa-node-demo
    • Install the necessary dependencies using the package.json file.
     $ npm install
    • Edit the config.js file. Replace the auth placeholders with your authentication credentials from the Plivo console. Enter your PHLO ID, which you can find on the Plivo console. Replace the phone number placeholder with an actual phone number in E.164 format (for example, +12025551234). Configuration file

    A review of the code

    Let‘s walk through what the code does.

    Step 1: Generate the OTP

    We use the Time-Based OTP algorithm to generate a random six-digit one-time password (OTP).

    1
    
    const code = Math.floor(100000 + Math.random() * 900000);
    

    Step 2: Send SMS and make a call

    With a single function, we can send an SMS message or make a call via PHLO (in the event the initial SMS message never arrives). The argument that tells PHLO whether to send an SMS message or make a call is mode, and the allowed values passed to it are sms and call.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    sendVerificationCode_phlo(DstNumber, mode) {
            var payload = {
                from: this.app_number,
                to: DstNumber,
                otp: code,
                mode: mode
            }
            phloClient = this.phlo_client
            phloClient.phlo(this.phloId).run(payload).then(function() {
                return code;
            }).catch(function(err) {
                console.error('Phlo run failed', err);
            });
        }
    

    Step 3: Verify the OTP

    We verify the OTP the user enters on their handset.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    router.get('/checkcode/:number/:code', function(req, res) {
        const number = (req.params.number);
        const code = (req.params.code);
        redisClient.get(`number:${number}:code`, function(err, OriginalCode) {
            if (OriginalCode == code) {
                redisClient.del(`number:${number}:code`);
                res.send(JSON.stringify({
                    'status': 'success',
                    'message': 'codes match, number verified'
                }));
            } else if (OriginalCode != code) {
                res.send(JSON.stringify({
                    'status': 'failure',
                    'message': 'codes do not match, number not verified'
                }));
            } else {
                res.send(JSON.stringify({
                    'status': 'failure',
                    'message': 'number not found'
                }));
            }
        });
    });
    

    Test

    To test the application, start the Redis server.

     $ redis-server

    Run the application.

    $ cd src/
    $ node app.js
    

    Set up ngrok to expose your local server to the internet.

    You should be able to see the application in action at https://<ngrok_identifier>.ngrok.io/.

    The finished application should look like this. Two-Factor Authentication

    Note: If you’re using a Plivo Trial account, you can make calls only to phone numbers that have been verified with Plivo. You can verify (sandbox) a number by going to the console’s Phone Numbers > Sandbox Numbers page.

    Here’s how to implement 2FA using Plivo APIs.

    Prerequisites

    To get started, you need a Plivo account — sign up with your work email address if you don’t have one already. If this is your first time using Plivo APIs, follow our instructions to set up a Node.js development environment.

    Set up the demo application locally

    • Clone the 2FA demo repository from GitHub.
     $ git clone https://github.com/plivo/2fa-node-demo.git
    • Change your working directory to 2fa-node-demo.
     $ cd 2fa-node-demo
    • Install the dependencies using the package.json file.
     $ npm install
    • Edit config.js. Replace the auth placeholders with your authentication credentials from the Plivo console. Replace the phone number placeholder with an actual phone number in E.164 format (for example, +12025551234). Replace the PHLO ID with null. Configuration file

    A review of the code

    Let‘s walk through what the code does.

    Step 1: Generate the OTP

    Use the Time-Based OTP algorithm to generate a random six-digit one-time password (OTP).

    1
    
    const code = Math.floor(100000 + Math.random() * 900000);
    

    Step 2: Send an SMS message with the OTP

    Send an SMS message with the OTP to the user’s registered mobile number using Plivo’s Send Message API.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    sendVerificationCode_sms(DstNumber, Message) {
            const code = Math.floor(100000 + Math.random() * 900000);
            const response = this.client.messages.create(
                {
                    src: this.app_number,, 
                    dst: DstNumber,
                    text: Message.replace('__code__', code));,
                }
            return code;
        }
    

    Failover: Make a phone call with the OTP

    If the SMS message doesn’t reach the mobile device, the user can request a voice OTP.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    sendVerificationCode_call(DstNumber) {
            const code = Math.floor(100000 + Math.random() * 900000);
            this.client.calls.create(
                this.app_number, // CallerId/Source
                DstNumber, // Destination
                'https://twofa-answerurl.herokuapp.com/answer_url/' + code); // Answer_url
            return code;
    
        }
    

    Step 3: Verify the OTP

    Verify the OTP the user entered on their handset.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    router.get('/checkcode/:number/:code', function(req, res) {
        const number = (req.params.number);
        const code = (req.params.code);
        redisClient.get(`number:${number}:code`, function(err, OriginalCode) {
            if (OriginalCode == code) {
                redisClient.del(`number:${number}:code`);
                res.send(JSON.stringify({
                    'status': 'success',
                    'message': 'codes match, number verified'
                }));
            } else if (OriginalCode != code) {
                res.send(JSON.stringify({
                    'status': 'failure',
                    'message': 'codes do not match, number not verified'
                }));
            } else {
                res.send(JSON.stringify({
                    'status': 'failure',
                    'message': 'number not found'
                }));
            }
        });
    });
    

    Test

    To test the application, start the Redis server.

     $ redis-server

    Save your code and run it.

    $ node app.js
    

    Set up ngrok to expose your local server to the internet.

    You should be able to see the application in action at https://<ngrok_identifier>.ngrok.io/.

    The finished application should look like this. Two-Factor Authentication

    Note: If you’re using a Plivo Trial account, you can make calls only to phone numbers that have been verified with Plivo. You can verify (sandbox) a number by going to the console’s Phone Numbers > Sandbox Numbers page.