ASP.NET Core 3.1 - 2FA QR Code Generator
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 downloaded the ASP.NET Core 3.1 - Users Without Identity Project or 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
Creation Series
- ASP.NET Core 3.1 - Users Without Identity
- ASP.NET Core 3.1 - User Entity
- ASP.NET Core 3.1 - Password Hasher
- ASP.NET Core 3.1 - User Management
- ASP.NET Core 3.1 - Admin Role
- ASP.NET Core 3.1 - Cookie Validator
- ASP.NET Core 3.1 - Concurrency Conflicts
- ASP.NET Core 3.1 - Must Change Password
- ASP.NET Core 3.1 - User Database Service
- ASP.NET Core 3.1 - Rename Related Entities
2FA Series
- ASP.NET Core 3.1 - 2FA Without Identity
- ASP.NET Core 3.1 - 2FA User Tokens
- ASP.NET Core 3.1 - 2FA Cookie Schemes
- ASP.NET Core 3.1 - 2FA Authenticating
- ASP.NET Core 3.1 - 2FA Sign In Service
- ASP.NET Core 3.1 - 2FA QR Code Generator
- ASP.NET Core 3.1 - Admin 2FA Requirement
- ASP.NET Core 3.1 - 2FA Admin Override
Enhanced User Series
- ASP.NET Core 3.1 - Enhanced User Without Identity
- ASP.NET Core 3.1 - 2FA Recovery Codes
- ASP.NET Core 3.1 - Login Lockout
- ASP.NET Core 3.1 - Created And Last Login Date
- ASP.NET Core 3.1 - Security Stamp
- ASP.NET Core 3.1 - Token Service
- ASP.NET Core 3.1 - Confirmed Email Address
- ASP.NET Core 3.1 - Password Recovery
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>
Update 02/23/2021
I added the Enhanced User Series' article links.
Comments(0)