Part Three: Verify Phone Numbers With Node.js Using Twilio SMS, Express and Socket.io

August 29, 2013
Written by
Jonathan Gottfried
Contributor
Opinions expressed by Twilio contributors are their own

Jon Gottfried

Every problem you solve as a web application developer requires a very particular set of tools. Tools that have been acquired over a very long career.

Node.js is one of the latest frameworks to become a popular addition to the modern web stack. It allows you to easily build lightweight, event-driven applications that can handle a large amount of concurrent I/O.

We have already helped you build phone verification systems to help secure your PHP and Ruby systems, but now you can use the same techniques to secure your brand new Node.js applications so that you can be sure that the user you are communicating with is always the expected one. Any time that you are interacting with a user via their phone number, you will need a way to confirm their identity. Confirming that a user owns the phone number they provided to your service helps you to decrease fraud and spam rates. Verifying a number also ensures that the user did not make a mistake when entering their phone number during registration.

In this post we will be building an SMS phone verification system using Node.js, Express , and Socket.io – unlike our previous tutorials in this series, this one will utilize websockets to let the user seamlessly interact with our application without reloading the page or having any hard refreshes or redirects.

We will go over the entire sample application piece by piece, but if you would like to download the complete example you can find it on Github here. This application will run in your local environment, but you can deploy it to your Node.js hosting platform of choice or use our techniques to integrate it into your production application as well.

Part One: Setting Up Our Node.js Application

The first thing we will do is configure our basic Node.js application. We will need to create a data directory, a views directory, and a package.json file with the following contents:

{
    "name": "TwilioNodePhoneVerification",
    "version": "0.0.1",
    "author": "Jon Gottfried <jonmarkgo@twilio.com>",
    "description": "a simple example of verifying a user's phone number using Node.js and Twilio",
    "repository": {
        "type": "git",
        "url": "https://github.com/jonmarkgo/TwilioNodePhoneVerification.git"
    },
    "dependencies": {
        "socket.io": "0.9.x",
        "twilio": "1.1.x",
        "express": "3.3.x",
        "jade": "0.34.x",
        "nstore": "0.5.x",
        "speakeasy": "1.0.x"
    },
    "engines": {
        "node": ">=0.10"
    }
}

We chose some specific dependencies for the purposes of this tutorial, though you may certainly use different modules in a production application if you prefer:

  • Socket.io is the simplest way to work with websockets in Node.js and makes it easy for us to add realtime interaction to our applications
  • Twilio allows us to easily access Twilio’s REST API without manually crafting our own HTTP requests
  • express is a lightweight Node.js web application framework and the most commonly used web framework for Node.js
  • Jade is a simple templating engine that plays well with express
  • nstore is a simple database written for Node.js – it works fine for the purposes of the tutorial but in a production application we would recommend using a more mature database such as MongoDB or PostgreSQL
    speakeasy (https://github.com/markbao/speakeasy) makes it easy to generate
  • speakeasy makes it easy to generate secure one-time passwords using Node.js

Once you have configured your packages.json file, run npm install in your Terminal to install all of our required modules. Then we can start writing some code!

Part Two: Writing Our View Using Jade

In the view folder that we created earlier, make a new file called index.jade – this will be our single-page view for the application. It is written in the jade templating engine, which is a simple way to create templates in Node.js – our file is fairly simple as well, we start out with our header block that contains all of the necessary JavaScript for our application:

!!! 5
html
  head
    script(src="/socket.io/socket.io.js")
    script(src="http://code.jquery.com/jquery-2.0.3.min.js")
    script
      var socket = io.connect();

      $(function() {
        $("#register_button").on("click", function(event) {
          event.preventDefault();
          socket.emit("register", {
            phone_number: $("#phone_number").val()
          });
        });

        $("#verify_button").on("click", function(event) {
          event.preventDefault();
          socket.emit("verify", {
            phone_number: $("#phone_number").val(),
            code: $("#code").val()
          });
        });

        socket.on("code_generated", function(data) {
          $("#register").fadeOut();
          $("#verify").fadeIn();
          $("#update").fadeOut();
          $("#register_instructions").fadeOut();
          $("#verify_instructions").fadeIn();
        });

        socket.on("update", function(data) {
          $("#update").html(data.message);
          $("#update").fadeIn();
        });

        socket.on("reset", function(data) {
          $("#register_instructions").fadeIn();
          $("#verify_instructions").fadeOut();
          $("#update").fadeOut();
          $("#register").fadeIn();
          $("#verify").fadeOut();
        });

        socket.on("verified", function(data) {
          $("#register").fadeOut();
          $("#verify").fadeOut();
          $("#register_instructions").fadeOut();
          $("#verify_instructions").fadeOut();
        });
      });

And then we end the file with our body block that contains all of our necessary form fields:

 body
    strong#update(style="display: none")
    p#register_instructions Enter your phone number:
    p#verify_instructions(style="display: none") Enter your verification code:
    div#register
      form
        input(type="text")#phone_number
        input(type="submit", value="Register")#register_button
    div#verify(style="display: none")
      form
        input(type="text")#code
        input(type="submit", value="Verify")#verify_button

Our form setup is fairly straightforward. We begin by showing the user the registration form with a hidden verification form in the background. Our Javascript code instantiates a connection to our socket.io websockets server, and sets up a number of hooks for various socket.io events as well as user-initiated form events. Socket.io provides a very straightforward API to using websockets, which allow for simple real-time interaction between our client and server. We hook actions to events from the server using socket.on and we emit events that the server is listening for using socket.emit

When the user clicks the Register button, we emit the phone number that they entered to the server. The server then responds with a code_generated event, which hides our registration form and displays our verification form. When the user enters their verification code and clicks Verify, we emit the code to the server and listen for the “verified” event as a response.

We also have two helper events, reset and update. reset brings the form back to its original state, and update changes the alert message being displayed to the user. That’s it for our view – it is very simple and is contained within a single page!

Part Three: Writing Our Node.js Application Code

Now we’re left with the meat of the application, where we interact with Twilio, our datastore, and our client application via socket.io – the first thing we must do is create a file called app.js and add the following code to it:

var app = require('express')()
  , http = require('http')
  , server = http.createServer(app)
  , io = require('socket.io').listen(server)
  , nStore = require('nstore')
  , client = require('twilio')(process.env.account_sid, process.env.auth_token)
  , speakeasy = require('speakeasy');

var users = nStore.new('data/users.db', function () {
  console.log("Loaded users.db");
});

server.listen(3000);

app.get('/',function(req,res){
  res.render('index.jade')
});

This code requires all of our necessary modules, loads up our database, and starts up a new webserver on port 3000 with a single route - / - that renders our jade template.
Next we set up a few basic functions for our application, createUser and checkVerified:

function createUser(phone_number, code, socket) {
  users.save(phone_number, {code: code, verified: false}, function (saverr) {
    if (saverr) { throw saverr; }
    client.sendSms({
        to: phone_number,
        from: process.env.twilio_number,
        body: 'Your verification code is: ' + code
    }, function(twilioerr, responseData) {
      if (twilioerr) { 
        users.remove(phone_number, function(remerr) {if (remerr) { throw remerr; }});
        socket.emit('update', {message: "Invalid phone number!"});
      } else {
        socket.emit('code_generated');
      }
    });
  });
}

function checkVerified(socket, verified, number) {
  if (verified == true) {
    socket.emit('reset');
    socket.emit('update', {message: "You have already verified " + number + "!"});
    return true;
  }
  return false;
}

Our createUser function takes in a phone number, verification code, and socket object. We then attempt to save a new entry in the database and send an SMS to the provided phone number with the verification code. We also emit an error to the user if we failed to send an SMS to their phone number.

In our checkVerified function, we simply check to see if our user is already verified or not and we emit an alert to tell the user that they cannot verify the same number twice.

Next we can dive in to our socket handling code:

io.sockets.on('connection', function(socket) {
  console.log('socket.io connected');
  socket.on('register', function(data) {
    var code = speakeasy.totp({key: 'abc123'});
    users.get(data.phone_number, function (geterr, doc, key) {
      if (geterr) {
        createUser(data.phone_number, code, socket);
      }
      else if (checkVerified(socket, doc.verified, data.phone_number) == false) {
        socket.emit('update', {message: "You have already requested a verification code for that number!"});
        socket.emit('code_generated');
      }
    });

  });

  socket.on('verify', function(data) {
    var code = Math.floor((Math.random()*999999)+111111);
    users.get(data.phone_number, function (geterr, doc, key) {
      if (geterr) {
        socket.emit('reset');
        socket.emit('update', {message: "You have not requested a verification code for " + data.phone_number + " yet!"});
      }
      else if (checkVerified(socket, doc.verified, data.phone_number) == false && doc.code == parseInt(data.code)) {
        socket.emit('verified');
        socket.emit('update', {message: "You have successfully verified " + data.phone_number + "!"});
        users.save(data.phone_number, {code: parseInt(data.code), verified: true}, function (saverr) { if (saverr) { throw saverr; }});
      }
      else {
        socket.emit('update', {message: "Invalid verification code!"});
      }
    });

  });
});

Once our websocket connection to the client is opened successfully, we register handlers for two events – register and verify.

Our register event takes in a phone number from the client, generates a secure one time password using the speakeasy module, and then looks up the phone number in our datastore. If the number does not exist, we attempt to create a new entry in the database. If it does exist, we display an alert that the user has already requested a verification code or alternatively show the alert that they have already successfully verified their number.
Our verify event takes in a phone number and code from the client. We look up the phone number in the database and throw an error if they have not yet requested a code. If they have requested a code already, we check to see if they have already verified their number successfully. If they have not, we check to make sure their code is correct, update the database entry, and alert the user that they successfully verified their number. If their code is incorrect, we alert them and allow them to re-enter it.

Overall, this is a fairly simple and robust example for how to verify a user’s phone number using Twilio SMS and Node.js

In order to run your application, you will need to define your necessary environment variables: account_sid, auth_token, and twilio_number – these can all be found in your Twilio account dashboard and you can set them on your system with the following commands:

export account_sid=ACxxxxxxxxxxxxxxxxxxxxxxxx
export auth_token=yyyyyyyyyyyyyyyyyyyyyyyyy
export twilio_number=+12121234567

Then you can run the application with the node app command and visit http://localhost:3000/ in your browser to try it out!

If you would like to see the full, working example you can find it on Github

If you have any questions or comments please tweet @jonmarkgo or e-mail jonmarkgo@twilio.com!