ASP.NET Core 3.1 - 2FA QR Code Generator


Ken Haggerty
Created 08/26/2020 - Updated 08/31/2020 06:29

This article will demonstrate the implementation of qrcode.js to display the 2FA authenticator key in a QR Code formatted image. I will assume you have created a new ASP.NET Core 3.1 Razor Pages project. See Tutorial: Get started with Razor Pages in ASP.NET Core. You should review the earlier articles of the Users Without Identity Project series.

Users Without Identity Project and Article Series

Access to the research project source code may be purchased on KenHaggerty.Com at Manage > Assets. A project which implements users without Identity has been published to demo.kenhaggerty.com. I enjoy writing these articles. It often enhances and clarifies my coding. The research project is a result of a lot of refactoring and hopefully provides logical segues for the articles. Thank you for supporting my efforts.

The ASP.NET Core Identity UI displays the authenticator key as text. I implemented qrcode.js complete with CDN link and integrity check to display the key in a QR Code formatted image. Mobile authenticator apps can use the image and the phone's camera to input the key.

The EnableAuthenticator page from the scaffolded Identity UI uses a method, LoadSharedKeyAndQrCodeUriAsync to format the key and the QR Code Uri. Notice the page property, AuthenticatorUri is set with the QR Code Uri.

See EnableAuthenticator.cshtml.cs:
private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";

private async Task LoadSharedKeyAndQrCodeUriAsync(AppUser user)
{
    // Load the authenticator key & QR code URI to display on the form
    var unformattedKey = await _userService.GetAuthenticatorKeyAsync(user.Id);
    if (string.IsNullOrEmpty(unformattedKey))
    {
        await _userService.ResetAuthenticatorKeyAsync(user.Id);
        unformattedKey = await _userService.GetAuthenticatorKeyAsync(user.Id);
    }

    SharedKey = FormatKey(unformattedKey);
    var name = User.FindFirst(ClaimTypes.Name).Value;
    AuthenticatorUri = GenerateQrCodeUri(name, unformattedKey);
}

private string FormatKey(string unformattedKey)
{
    var result = new StringBuilder();
    int currentPosition = 0;
    while (currentPosition + 4 < unformattedKey.Length)
    {
        result.Append(unformattedKey.Substring(currentPosition, 4)).Append(" ");
        currentPosition += 4;
    }
    if (currentPosition < unformattedKey.Length)
        result.Append(unformattedKey.Substring(currentPosition));

    return result.ToString().ToLowerInvariant();
}

private string GenerateQrCodeUri(string name, string unformattedKey)
{
    return string.Format(AuthenticatorUriFormat, _urlEncoder.Encode("Users Without Identity"),
        _urlEncoder.Encode(name), unformattedKey);
}

Add qrcode.js to libman.json. See ASP.NET Core 2.2 - Manage Client-Side Libraries

Edit libman.json:
{
  "destination": "wwwroot/lib/qrcode/",
  "files": [
    "qrcode.js",
    "qrcode.min.js"
  ],
  "library": "qrcodejs@1.0.0"
}

Add the CDN link for qrcode.js to the EnableAuthenticator page.

<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"
    asp-fallback-src="~/lib/qrcode/qrcode.min.js"
    asp-fallback-test="window.QRCode"
    integrity="sha512-CNgIRecGo7nphbeZ04Sc13ka07paqdeTu0WR1IM4kNcpmBAUSHSQX0FslNhTDadL4O5SAGapGt4FodqL8My0mA=="
    crossorigin="anonymous">
</script>

The EnableAuthenticator page uses a div to display the image.

<div id="qrCode"></div>

Use JavaScript on the page to configure the size and load the image.

<script>
    new QRCode(document.getElementById("qrCode"),
        {
            text: "@@Html.Raw(Model.AuthenticatorUri)",
            width: 200,
            height: 200
        });
</script>
Configure App Page
Update 08/31/2020

I added the 2FA Admin Override article link.


Comment Count = 0

Please log in to comment or follow.

Login Register
Follow to get web notifications when new comments are posted to this article.
Logged in users receive web notifications for new articles, topics and assets.
Web Notifications