/verify-guide-csharp

Two-Factor Authentication (2FA) in C#

Primary LanguageC#

Two-Factor Authentication (2FA)

⏱ 20 min build time

Enterprises are increasingly challenged to keep sensitive information from falling into the wrong hands. This means that we can no longer trust old online authentication systems that rely solely on usernames and passwords, especially as security breaches grow in frequency, severity and sophistication.

With the MessageBird Verify API, you can implement two factor authentication (2FA) solutions to provide an additional layer of account security by verifying the user's password with a second authentication token and in turn, secure customer data, block fraudulent accounts, and safeguard key transactions in a matter of minutes. The most common use case involves the application of one-time passwords (OTP) generated by hardware tokens or authenticator apps or directly sent to the user's mobile phone via SMS text messaging.

In this MessageBird Developer's Guide, we'll introduce the MessageBird Verify API and show you how to build a runnable application in Node.js. The application is a prototype for a two factor authentication system deployed by our fictitious online banking application called BirdBank.

We'll walk you through the following steps:

  • Asking for the phone number
  • Sending a verification code
  • Verifying the code

Pro-tip: Follow this tutorial to build the whole application from scratch or, if you want to see it in action right away, you can download, clone or fork the sample application from the MessageBird Developer Guides GitHub repository.

Getting Started

We'll build the sample web application using Microsoft Visual Studio. To follow this Developer Guide and run the sample application, we'll need to have Visual Studio (2012 or later) installed. Learn more about the latest available Visual Studio editions here. Note that you'll need to install the Visual Studio edition that matches your usage scenario (explained in Supported Usage Scenarios).

Now, its time to download, clone or fork the sample web application from the MessageBird Developer Guides GitHub repository. Once you've done this, let's open the solution file verify-guide-csharp.sln in Visual Studio.

The solution file contains the verify-guide-csharp-project, which is where we've stored our application source files. The application is written using ASP.NET Web Forms, which is a simple ASP.NET framework. We use Web Forms to add some structure to the code and keep the web page presentation separate from processing logic. Later, we will explore the application source files.

But first, let's install the libraries (packages) that are needed to get our application working. On the main menu in Visual Studio, click Tools | NuGet Package Manager | Package Manager Console. The Package Manager Console will open and you will see a command prompt. Type each line below one-by-one and press ENTER after each line:

Install-Package Microsoft.Net.Compilers -ProjectName verify-guide-csharp-project -Version 2.8.2 Install-Package Microsoft.CodeDom.Providers.DotNetCompilerPlatform -ProjectName verify-guide-csharp-project -Version 2.0.0 Install-Package MessageBird -ProjectName verify-guide-csharp-project -Version 1.3.5.1 Install-Package Newtonsoft.Json -ProjectName verify-guide-csharp-project -Version 11.0.2 Install-Package DotNetEnv -ProjectName verify-guide-csharp-project -Version 1.2.0

The five packages are now installed! The Microsoft packages are low-level packages that are needed to use ASP.NET. The MessageBird package contains the Verify APIs. The DotNetEnv package will allow us to retrieve your API key as an environment variable.

We won't need to use the Package Manager Console window, so let's go ahead and close it.

Now, let's open the Solution Explorer. We will use it to view our project files. You should see the Solution Explorer open on the right - if not, go to View | Solution Explorer on the main menu in Visual Studio.

Creating the Master Page

Our sample application contains three web pages. To avoid coding the same header and footer HTML tags into each page, we've created a MasterPage.master file that specifies these tags. In this file, you will see these tags above and below the ContentPlaceHolder. The ContentPlaceHolder contains the unique content that is rendered on each page.

Asking for the Phone Number

The first step in verifying a user's phone number is asking them to provide their phone number. In Step1.aspx you'll find a basic HTML form with a phone number input text box and a button:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Step1.aspx.cs" Inherits="Step1" %>

<asp:Label id="ErrorLabel" runat="server"></asp:Label>
<p>Please enter your phone number (in international format, starting with +) to receive a verification code:</p>
<form id="Step1Form" runat="server">
    <asp:TextBox id="PhoneNumberTextBox" runat="server"></asp:TextBox>
    <asp:Button ID="SendCodeButton" runat="server" Text="Send code" 
        OnClick="SendCodeButton_Click"/>
</form>

When our user clicks on the button, the SendCodeButton_Click method runs on the code behind page. This method is shown below in Step1.aspx.cs:

// Using statements not included (for brevity)
public partial class Step1 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // Show an error if this page was previously called and CreateVerify generated an error
        if (Session["Error"] != null)
            ErrorLabel.Text = Session["Error"].ToString();
    }

    protected void SendCodeButton_Click(object sender, EventArgs e)
    {
        // Check if phone number is empty
        if (PhoneNumberTextBox.Text.Length == 0)
        {
            Session["Error"] = "Phone number cannot be empty.";
            Server.Transfer("Step1.aspx");
            return;
        }

        // Load the API key using the DotNetEnv library
        DotNetEnv.Env.Load(System.AppDomain.CurrentDomain.BaseDirectory + "/APIKey.env");
        String YourAccessKey = System.Environment.GetEnvironmentVariable("MESSAGEBIRD_API_KEY");

        // Initalize the MessageBird API
        MessageBird.Client client = MessageBird.Client.CreateDefault(YourAccessKey);

        Session["client"] = client;

        // Call CreateVerify to send a verification code to the user's phone. Here, we are sending "null" as the second
        // input. This input specifies optional settings, such as the timeout. Since we are sending "null", the default
        // timeout is used, which is 30 seconds.
        try
        {
            Verify verify = client.CreateVerify(PhoneNumberTextBox.Text, null);
            Session["VerifyId"] = verify.Id;
        }
        catch (ErrorException errorException)
        {
            Session["Error"] = ErrorGenerator.Generate(errorException);
            Server.Transfer("Step1.aspx");
        }
        Server.Transfer("Step2.aspx");
    }
}

Checking for an empty phone number

Right away, we check if the length of the phone number the user entered is 0. If it is, the phone number is empty and the user will be prompted to re-enter it. In this case, the page calls itself via Server.Transfer.

Retrieving the API Key

If the phone number is populated correctly, the application will retrieve your API key as an environment variable. This is done via the DotNetEnv library. Rather than hardcoding the API key directly in Step1.aspx.cs, we've created a separate APIKey.env file to store the key. You shouldn't hardcode API keys in any files that you will be storing in a version control system, such as Git and Team Foundation Version Control (TFVC). So, if you were to store this sample application in a version control system, you wouldn't add APIKey.env.

Now, to create the file, go to the Solution Explorer, right click "verify-csharp-project", click Add | Add New Item... In the name field, specify APIKey.env and click Add. With file now open, enter the line:

MESSAGEBIRD_API_KEY=YOUR-API-KEY

Replace YOUR-API-KEY with your API key. Keys can be created or retrieved from the API access (REST) tab in the Developers section of your MessageBird dashboard.

Switching back to Step1.aspx.cs, we initialize the MessageBird client API via the CreateDefault method and pass in your API key.

Next, we store a reference to the MessageBird client in an ASP.NET session variable. We'll use this this variable later.

Sending a Verification Code

Continuing with our walk-through of Step1.aspx.cs, we call the Verify method, which sends a verification code to the phone number that the user entered in the form. The MessageBird Verify API takes care of generating a random code, so you don't have to do this yourself. Codes are numeric and six digits by default. If you want to customize the length of the code or configure other options, you can check out the Verify API documentation.

If all is well, the page Step2.aspx is rendered. The details of this are explained in the Verifying the Code section below.

But, if there's an error while Verify executes, an ErrorException is thrown. We handle the exception by invoking the Generate method of the ErrorGenerator class. This class is stored in the ErrorGenerator.cs file in the App_Code folder. This Generate method builds the error string, which is then stored in a Session variable. Then the page calls itself via Server.Transfer. The Page_Load method detects that there is an error, so it populates the ErrorLabel on the form in Step1.aspx, which displays the error to the user. Then the user is prompted to enter their phone number again.

Verifying the Code

Once the code is delivered, our user will check their phone and enter the code into the textbox in the form in Step2.aspx below.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Step2.aspx.cs" Inherits="Step2" %>

<asp:Label id="ErrorLabel" runat="server"></asp:Label>
<p>We have sent you a verification code!</p>
<p>Please enter the code here:</p>
<form id="Step2Form" runat="server">
    <asp:TextBox id="CodeTextBox" runat="server"></asp:TextBox>
    <asp:Button ID="CheckCodeButton" runat="server" Text="Check code" 
        OnClick="CheckCodeButton_Click"/>
</form>

When the user clicks on the button, the CheckCodeButton_Click method runs on the code behind page Step2.aspx.cs: (Note the terms "code" and "token" used here mean the same thing).

// Using statements not included (for brevity)
public partial class Step2 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // Show an error if this page was previously called and SendVerifyToken generated an error
        if (Session["Error"] != null)
            ErrorLabel.Text = Session["Error"].ToString();
    }

    protected void CheckCodeButton_Click(object sender, EventArgs e)
    {
        // Check if code is empty
        if (CodeTextBox.Text.Length == 0)
        {
            Session["Error"] = "Verification code cannot be empty.";
            Server.Transfer("Step2.aspx");
            return;
        }

        // Call SendVerifyToken to verify the code entered in CodeTextBox.Text matches the code
        // sent to the user in the CreateVerify call in Step1.aspx.cs. Here, the words "token" and "code"
        // mean the same thing.
        try
        {
            Client client = ((Client)Session["Client"]);
            client.SendVerifyToken(Session["VerifyId"].ToString(), CodeTextBox.Text);
        }
        catch (ErrorException errorException)
        {
            Session["Error"] = ErrorGenerator.Generate(errorException);
            Server.Transfer("Step2.aspx");
        }
        Server.Transfer("Step3.aspx");
    }
}

Right away, we check if the length of the code the user entered is 0. If it is, the code is empty and the user needs to reprompted to enter it. In this case, the page calls itself via Server.Transfer.

If the code is populated, we call the SendVerifyToken method with two inputs: the code just entered by the user, and the VerifyId that was generated in Step1.aspx.cs as a result of calling the Verify method. (This VerifyId is stored in the Session variable)

SendVerifyToken verifies the code entered by the user matches the code sent to the user in the CreateVerify call in Step1.aspx.cs.

As before, there's a catch-block to handle errors such as an invalid token entered by the user. If there is an error, we show the same form again with the error.

If verification was successful, we render a simple confirmation page in Step3.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Step3.aspx.cs" Inherits="Step3" %>

<p>You have successfully verified your phone number.</p>

Testing

To test the application, click on Step1.aspx in the Solution Explorer. Then click on the green start button on the toolbar at the top.

Nice work!

You now have a running integration of MessageBird's Verify API using C#!

You can now leverage the flow, code snippets and UI examples from this tutorial to build your own two factor authentication system. Don't forget to download the code from the MessageBird Developer Guides GitHub repository.

Next steps

Want to build something similar but not quite sure how to get started? Please feel free to let us know at support@messagebird.com, we'd love to help!