https://a.storyblok.com/f/270183/1368x665/261b6977ca/multifactor-security-authentication.png

Improve Your Multifactor Auth With the Verify API and SIM Swap Insight

Time to read: 7 minutes

This article was last updated on 4 March 2026

Introduction

SIM Swap attacks pose many risks, including identity theft and identity takeover. This tutorial will show how to improve security when resetting passwords by checking whether your SIM card was swapped on your mobile phone and sending an SMS to recover your account. The flow uses the Verify API to verify a token and the Identity Insights API to detect if a SIM card was swapped in the last few days. If so, the verification code won't be sent.

Note: The Network Powered Solutions are available in the following countries and Communication Service Providers (CSPs)

Source Code

The application's source code can be found on our GitHub repo.

Prerequisites

  • Node.js and npm installed on your machine.

  • A code/text editor and basic JavaScript knowledge.

  • Vonage API Account

    To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

Application Architecture

The application follows a client-server architecture. The client handles user interactions through HTML and JavaScript, including entering phone numbers and submitting verification codes. The client and the server communicate via GET/POST requests. The server, developed in Node.js with Express, manages backend logic, including interfacing with Vonage's Identity Insights and Verify v2 APIs for security checks and authentication.

Create a New Project

Create a new project and change into its directory.

mkdir improve-your-auth && cd improve-your-auth

Start a New Node Project

In your newly created project directory, initialize a new Node project. This will create a new package.json file. The -y flag automatically fills in the defaults without asking for the details.

npm init -y

Install the Dependencies

To install all the dependencies in one go, run the following command. It will automatically add them to your package.json file and install them in your project's node_modules directory.

npm install @vonage/server-sdk @vonage/identity-insights dotenv express

Create a New Vonage Application

Now that we have specified the folders and dependencies we will use for the project, it's time to create a Vonage Application with Verify and Identity Insights capabilities.

After signing up/in for a Vonage account, you can create a new application in the dashboard by navigating to 'Your Applications', clicking 'Create a new application', giving it a name, such as 'multifactor authentication', and toggling Verify V2 and Network Powered Solutions.

Note: Register your application with Vonage and the Communication Service Providers (CSP) before using the Identity Insights API. If your registration is already approved, you can start building your solution right away. If not, check out our guide on Vonage Network Registration for more details.

Create a public/private key pair for API authentication; this will download a private.key. Add that file to your node project folder.

Server Side Implementation

Identity Insights SIM Swap Overview

The important aspect of the Identity Insights API we will use for this demonstration is its ability to check whether the swap occurred in the last few days, letting the user know there may have been potential fraud if the swap wasn't made by them.

The SIM Swap insight strengthens SIM-based authentication methods, including SMS One-Time Passwords and silent authentication. It tracks the last SIM swap for a specific mobile number and checks a SIM card's activation date in real time.

Create the Server File

The server.js file is our main server script that integrates with the Vonage Identity Insights and Verify v2 APIs to authenticate users securely. It also serves the web pages for our banking dashboard and handles user login and verification.

Set Up the Identity Insights Client

We initialize two clients at startup: the main Vonage client for Verify v2, and a dedicated IdentityInsights client for SIM Swap checks. Both authenticate using your application ID and private key, so there's no need to manage OAuth2 tokens manually.

const { Vonage } = require("@vonage/server-sdk");
const { Auth } = require("@vonage/auth");
const { Channels } = require("@vonage/verify2");
const { IdentityInsights } = require("@vonage/identity-insights");

const vonage = new Vonage(
  new Auth({
    applicationId: APPLICATION_ID,
    privateKey: keyContent,
  })
);

const identityClient = new IdentityInsights({
  applicationId: APPLICATION_ID,
  privateKey: keyContent,
});

SIM Swap Check

The checkSim function checks if the phone number has been swapped recently using the Identity Insights SDK. I've set a PERIOD environment variable that you can set to the number of hours ago you want to check to see if the SIM swap happened.

You can also use the SIM Swap Insight to get the date and time of the latest SIM swap performed. Learn more about making an API call with the SIM Swap Insight.

async function checkSim() {
  try {
    const resp = await identityClient.getIdentityInsights({
      phoneNumber: phoneNumber,
      purpose: "FraudPreventionAndDetection",
      insights: {
        simSwap: {
          period: parseInt(PERIOD),
        },
      },
    });

    return resp.insights?.simSwap?.isSwapped === true;
  } catch (error) {
    console.warn("Identity Insights SDK call failed:", error && error.message);
  }
}

Add Verify V2 API

In our use case, the Verify V2 API allows us to send a verification code to a user's phone number if no recent SIM swap has been detected.

SIM Swap Route

The /simswap route performs the SIM swap check separately, so the client can handle the result before deciding whether to request a verification code:

app.post("/simswap", async (req, res) => {
  phoneNumber = req.body.phone;
  try {
    const simSwapped = await checkSim();
    res.json({
      swapped: simSwapped,
    });
  } catch (error) {
    console.error("Error checking SIM swap:", error);
    res.status(500).json({ message: "Error processing request." });
  }
});

Verification Request

Below, we handle a verification request. Once the client has confirmed the SIM swap check result and the user chooses to proceed, we send a verification code using the Verify V2 API:

app.post("/sendcode", async (req, res) => {
  const phone = process.env.RECIPIENT_NUMBER ? process.env.RECIPIENT_NUMBER : req.body.phone;
  try {
    const response = await vonage.verify2.newRequest({
      brand: "Vonage Bank",
      workflow: [
        {
          channel: Channels.SMS,
          to: phone,
        },
      ],
    });
    verifyRequestId = response.requestId;
    res.json({
      message: "Verification code sent.",
      verifycode: true,
      request_id: verifyRequestId,
    });
  } catch (error) {
    console.error("Error during verification:", error);
    res.status(500).json({ message: "Error processing request.", verifycode: false });
  }
});

PIN Submission

Once the user receives their code, submitting it is straightforward:

app.post("/verify", (req, res) => {
  const { pin, newPass } = req.body;
  vonage.verify2
    .checkCode(verifyRequestId, pin)
    .then((status) => {
      if (status === "completed") {
        const user = Object.values(users).find(user => user.username === "user1");
        if (user) {
          user.password = newPass;
        } else {
          res.status(404).json({ message: "User not found." });
          return;
        }
        res.json({ message: "Success" });
      } else {
        res.json({ message: "Invalid verification code. Please try again." });
      }
    })
    .catch((err) => {
      console.error("Error during PIN verification:", err);
      res.status(500).json({ message: "Error during PIN verification." });
    });
});

Create the Environment Variables File

Create a .env file for your project and add the environment variables found in the code snippet below. Refer to Michael's blog post for a wonderful explanation of using environment variables in Node.js.

The VONAGE_API_SECRET and VONAGE_API_SECRET can be found on the Vonage Dashboard.

It shows where the API Key and API Secrets are. Right under the text API key and API Secret]Vonage Dashboard

# Your Vonage application 
VONAGE_APPLICATION_ID=your_application_id
VONAGE_PRIVATE_KEY=/path/to/your/private.key


# Number of hours to check SIM Swap events
PERIOD=72

Client Side Implementation

Add the Content and Styling

In the index.html file, we will add two forms: one for entering a phone number and another for logging in with a PIN. This layout enables the user to authenticate their identity securely. For simplicity and clarity, I am leaving the password in plain text. Of course, in real-life/production scenarios, you'll need to encrypt the password and eventually add a Salt value to strengthen security.

In the main.html file, we will have our bank dashboard, which is accessible once the user successfully logs in.

The style.css file contains the styling for both HTML files. You can use the simple styles I've added for this project, or be creative and create your own!

Add the client.js File

In the client.js file, we handle form submissions on our website. It manages the steps where users enter their phone numbers and receive a verification code if their SIM card hasn't been swapped recently.

The script quickly lets users know whether they can't be authenticated due to a recent SIM swap or if they'll receive a code to proceed with logging in. This ensures that only users with secure accounts can access sensitive features.

Test It Out

To see everything in action, start up the application by running:

node server.js

Then, open your web browser and navigate to:

http://localhost:3000/

Here's what you should expect: imagine you've forgotten your password. Click on 'Forgot Password' to start the recovery. You'll be prompted to enter your phone number and request verification.

If the application detects a recent SIM swap, a warning pops up: “Warning! A recent SIM pairing change occurred for the User's mobile account. Proceed?" If you didn't initiate this swap and choose 'No, it wasn't me', it's a sign that there might be fraud with your number. This is your cue to check in with your mobile provider.

Note: In the demonstration, you're prompted to confirm that you've swapped the SIM card; in a real-life scenario, the user would likely be invited to contact the service provider directly for additional identity checks.

Similarly, this approach could be applied to multifactor authentication on login, where a check would occur before sending the one-time token; if a recent SIM swap is detected, the user would be invited to contact the service provider directly for additional identity checks.

On the other hand, if you swapped your SIM and selected 'Yes, it was me,' the app uses the Verify API to send a verification code to your phone. Enter this code on the next screen and set a new password. Once that's done, you can use your new credentials to log into your simulated bank account.

Conclusion

Congratulations, you've reached the end of this tutorial! You've learned to use the Verify API to verify a token and the SIM Swap Insight to detect if the phone number was swapped in the last few days.

Have a question or something to share? Join the conversation on the Vonage Community Slack, stay up to date with the Developer Newsletter, follow us on X (formerly Twitter), subscribe to our YouTube channel for video tutorials, and follow the Vonage Developer page on LinkedIn, a space for developers to learn and connect with the community. Stay connected, share your progress, and keep up with the latest developer news, tips, and events!

Share:

https://a.storyblok.com/f/270183/400x400/3f6b0c045f/amanda-cavallaro.png
Amanda CavallaroDeveloper Advocate