In this article I will explain with an example, how to implement 2 Factor Authentication (TOTP) using Microsoft Authenticator App in ASP.Net using C# and VB.Net.
This article makes use of OtpSharp library for implementing TOTP.
 
 

What is TOTP?

TOTP stands for Time-based one-time password.
It is basically a Two Factor authentication where a temporary OTP (One-Time-Password) is generated.
TOTP is also known as app based authentication, software tokens or soft tokens.
The OTP is generated using current Server time for uniqueness.
TOTP uses Shared Key Authentication (SKA) by which it gains the access of wireless network or device.
 
 

Advantages of TOTP

1. It is lightweight.
2. It provides quicker authentication.
3. It is easy to implement as compared to other authentications like hardware tokens, Biometric authentication and etc.
4. TOTP makes your online account more secured by adding extra layers of security.
5. It provides offline supports as the Microsoft Authenticator can generate OTP without the internet connection.
 
 

Installing OtpSharp.Core package using Nuget

In order to install OtpSharp.Core library using Nuget, please refer my article Install OtpSharp.Core library using Nuget.
 
 

Installing QRCoder package using Nuget

In order to install QRCoder library using Nuget, please refer my article Install QRCoder library using Nuget.
 
 

Installing Microsoft Authenticator App

In order to install Microsoft Authenticator app, first search for Microsoft Authenticator in Google Play store or App store and click on Install.
Implement 2 Factor Authentication (TOTP) using Microsoft Authenticator App in ASP.Net
 
Or you can download and install the Microsoft Authenticator app using the following link.
 
 

HTML

The HTML markup consists of following controls:
Image – For displaying QR code.
HiddenField – For storing shared secret key.
TextBox – For capturing OTP.
Button – For validating OTP entered in the TextBox.
The Button has been assigned with an OnClick event handler.
Label – For displaying appropriate message based on validation of OTP.
<asp:Image ID="imgQRCode" runat="server" Width="200" Height="200" />
<asp:HiddenField ID="hfSecretKey" runat="server" />
<br />
<asp:TextBox ID="txtOTP" runat="server" placeholder="Enter OTP"></asp:TextBox>
<asp:Button ID="btnValidate" runat="server" Text="Validate OTP" OnClick="OnValidate" />
<br /><br />
<asp:Label ID="lblMessage" runat="server"></asp:Label>
 
 

Namespaces

You will need to import the following namespaces.
C#
using System.IO;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Security.Cryptography;
using OtpSharp;
using QRCoder;
 
VB.Net
Imports System.IO
Imports System.Text
Imports System.Drawing
Imports System.Drawing.Imaging;
Imports System.Security.Cryptography
Imports OtpSharp
Imports QRCoder
 
 

Generating OAUTH URI and QRCode for TOTP authentication

Inside the Page_Load event handler, issuer name and account name is set and issuer name is encoded using UrlEncode method of HttpUtility class which will be used later to construct the URI and random secret key is generated using the GenerateRandomKey method.
 

Generating Random Secret Key

Inside the GenerateRandomKey method, an object of RNGCryptoServiceProvider class is created and based on the length, the secretKey is generated and returned.
Then, the generated secret key is stored into a HiddenField and encoded into BYTE Array and then converted into BASE32 string.
Once the encoded secret key is ready, the URI is generated using the following parameters:
Issuer – Name of issuer.
Account – The email account.
Secret Key – BYTE array of secret key generated earlier in this code.
OtpHashMode – Used for calculating the code in OTP (One Time Password).
After that, the QR code is generated for the URI and displayed using Image control.
Note: For more details on generating and displaying QR code, please refer my article Dynamically generate and display QR code Image in ASP.Net.
 
C#
protected void Page_Load(object sender, EventArgs e)
{
    if (!this.IsPostBack)
    {
        string issuer = "ASPSnippets";
        string account = "queries@aspsnippets.com";
        string encodedIssuer = HttpUtility.UrlEncode(issuer);
 
        // Generate random secret key.
        string secretKey = this.GenerateRandomKey(20);
        // Storing the secret key.
        hfSecretKey.Value = secretKey;
        string encodedSecretKey = this.ToBase32String(Encoding.UTF8.GetBytes(secretKey));
 
        // Generate OAuthUri.
        string otpAuthUri = string.Format("otpauth://totp/{0}:{1}?secret={2}&{3}&issuer={4}&algorithm={5}", issuer, account, encodedSecretKey.Trim('='), secretKey, encodedIssuer, OtpHashMode.Sha1);
 
        // Generate QR code image.
        using (QRCodeGenerator qrGenerator = new QRCodeGenerator())
        {
            using (QRCodeData qrCodeData = qrGenerator.CreateQrCode(otpAuthUri, QRCodeGenerator.ECCLevel.Q))
            {
                using (QRCode qrCode = new QRCode(qrCodeData))
                {
                    using (Bitmap qrCodeImage = qrCode.GetGraphic(20))
                    {
                        // Convert QR code image to byte array.
                        using (MemoryStream stream = new MemoryStream())
                        {
                            qrCodeImage.Save(stream, ImageFormat.Png);
                            byte[] bytes = stream.ToArray();
                            string base64String = Convert.ToBase64String(bytes);
 
                            // Display QR code.
                            imgQRCode.ImageUrl = "data:image/png;base64," + base64String;
                        }
                    }
                }
            }
        }
    }
}
 
private string GenerateRandomKey(int length)
{
    using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
    {
        byte[] key = new byte [length];
        rng.GetBytes(key);
        return Convert.ToBase64String(key);
    }
}
 
private static string ToBase32String(byte[] data)
{
    // Base32 character set.
    const string base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
    StringBuilder result = new StringBuilder((data.Length * 8 + 4) / 5);
 
    int buffer = data[0];
    int next = 1;
    int bitsLeft = 8;
    while (bitsLeft > 0 || next < data.Length)
    {
        if (bitsLeft < 5)
        {
            if (next < data.Length)
            {
                buffer <<= 8;
                buffer |= data[next++] & 0xFF;
                bitsLeft += 8;
            }
            else
            {
                int pad = 5 - bitsLeft;
                buffer <<= pad;
                bitsLeft += pad;
            }
        }
        int index = 0x1F & (buffer >> (bitsLeft - 5));
        bitsLeft -= 5;
        result.Append(base32Chars[index]);
    }
    return result.ToString();
}
 
VB.Net
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    If Not Me.IsPostBack Then
        Dim issuer = "ASPSnippets"
        Dim account = "queries@aspsnippets.com"
        Dim encodedIssuer As String = HttpUtility.UrlEncode(issuer)
 
        ' Generate random secret key.
        Dim secretKey As String = Me.GenerateRandomKey(20)
        ' Storing the secret key.
        hfSecretKey.Value = secretKey
        Dim encodedSecretKey As String = Me.ToBase32String(Encoding.UTF8.GetBytes(secretKey))
 
        ' Generate OAuthUri.
        Dim otpAuthUri = String.Format("otpauth://totp/{0}:{1}?secret={2}&{3}&issuer={4}&algorithm={5}", issuer, account, encodedSecretKey.Trim("="c), secretKey, encodedIssuer, OtpHashMode.Sha1)
 
        ' Generate QR code image.
        Using qrGenerator As QRCodeGenerator = New QRCodeGenerator()
            Using qrCodeData As QRCodeData = qrGenerator.CreateQrCode(otpAuthUri, QRCodeGenerator.ECCLevel.Q)
                Using qrCode As QRCode = New QRCode(qrCodeData)
                    Using qrCodeImage As Bitmap = qrCode.GetGraphic(20)
                        ' Convert QR code image to byte array.
                        Using stream As MemoryStream = New MemoryStream()
                            qrCodeImage.Save(stream, ImageFormat.Png)
                            Dim bytes As Byte() = stream.ToArray()
                            Dim base64String = Convert.ToBase64String(bytes)
 
                            ' Display QR code.
                            imgQRCode.ImageUrl = "data:image/png;base64," & base64String
                        End Using
                    End Using
                End Using
            End Using
        End Using
    End If
End Sub
 
Private Function GenerateRandomKey(length As Integer) As String
    Using rng = New RNGCryptoServiceProvider()
        Dim key = New Byte(length - 1) {}
        rng.GetBytes(key)
        Return Convert.ToBase64String(key)
    End Using
End Function
 
Private Function ToBase32String(data As Byte()) As String
    ' Base32 character set.
    Const base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
    Dim result As StringBuilder = New StringBuilder(Convert.ToInt32((data.Length * 8 + 4) / 5))
 
    Dim buffer As Integer = data(0)
    Dim [next] = 1
    Dim bitsLeft = 8
    While bitsLeft > 0 OrElse [next] < data.Length
        If bitsLeft < 5 Then
            If [next] < data.Length Then
                buffer <<= 8
                buffer = buffer Or data(Math.Min(Threading.Interlocked.Increment([next]), [next] - 1)) And &HFF
                bitsLeft += 8
            Else
                Dim pad = 5 - bitsLeft
                buffer <<= pad
                bitsLeft += pad
            End If
        End If
        Dim index = &H1F And buffer >> bitsLeft - 5
        bitsLeft -= 5
        result.Append(base32Chars(index))
    End While
    Return result.ToString()
End Function
 
 

Validating OTP generated from Microsoft Authenticator App

When the Validate OTP Button is clicked, the secret key is fetched from HiddenField and converted into BYTE array using GetBytes method of Encoding class.
Then, an instance of Totp class is created which accepts the following parameters.
Secret Key – BYTE array of secret key generated earlier in this code.
step – It defines the time interval within which the generated OTP will be valid. In this case it is 30 seconds.
mode – The OtpHashMode value is set to Sha1.
size – The length of the OTP to be generated. In this case it is 6.
Finally, the OTP is validated using the VerifyTotp method of Totp class and an appropriate message is displayed in the Label.
C#
protected void OnValidate(object sender, EventArgs e)
{
    byte[] secretKeyBytes = Encoding.UTF8.GetBytes(hfSecretKey.Value);
 
    // Validate the OTP.
    Totp totp = new Totp(secretKeyBytes, step: 30, mode: OtpHashMode.Sha1, totpSize: 6);
    bool isValid = totp.VerifyTotp(txtOTP.Text.Trim(), out long timeStepMatched, null);
 
    // Display the validation result.
    lblOTPValidation.Text = isValid ? "OTP is valid" : "OTP is invalid";
    lblMessage.ForeColor = isValid ? Color.Green : Color.Red;
}
 
VB.Net
Protected Sub OnValidate(sender As Object, e As EventArgs)
    Dim secretKeyBytes = Encoding.UTF8.GetBytes(hfSecretKey.Value)
 
    ' Validate the OTP.
    Dim totp As Totp = New Totp(secretKeyBytes, [step]:=30, mode:=OtpHashMode.Sha1, totpSize:=6)
    Dim timeStepMatched As Long = Nothing
    Dim isValid As Boolean = totp.VerifyTotp(txtOTP.Text.Trim(), timeStepMatched, Nothing)
 
    ' Display the validation result.
    lblMessage.Text = If(isValid, "OTP is valid", "OTP is invalid")
    lblMessage.ForeColor = If(isValid, Color.Green, Color.Red)
End Sub
 
 

Scanning QR code and generating TOPT using the Microsoft Authenticator app

After installing the app, open it and click on Add account.
Implement 2 Factor Authentication (TOTP) using Microsoft Authenticator App in ASP.Net
 
Then, choose the account type.
Implement 2 Factor Authentication (TOTP) using Microsoft Authenticator App in ASP.Net
 
After that select Scan a QR code option.
 
Implement 2 Factor Authentication (TOTP) using Microsoft Authenticator App in ASP.Net
 
Next, scan the QR code.
Once the account has been added, you will see your issuer name with account for which the OTP is generated.
Implement 2 Factor Authentication (TOTP) using Microsoft Authenticator App in ASP.Net
 
Finally, open the account and you will see the generated One-time password code.
Note: The generated OTP is valid for 30 seconds and after 30 seconds a new OTP will be generated.
 
Implement 2 Factor Authentication (TOTP) using Microsoft Authenticator App in ASP.Net
 
Enter the One-time password code in the TextBox and verify.
 
 

Screenshot

Implement 2 Factor Authentication (TOTP) using Microsoft Authenticator App in ASP.Net
 
 

Downloads