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)