How to enable and use Two factor authentication in Asp.Net Core 6.0 with Razor page Identity

Sherpa 181 Reputation points
2023-05-19T15:25:50.4366667+00:00
I am new to ASP.NET Core 6.0 Identity two-factor authentication. The latest identity framework added several Razor pages, which include `EnableAuthenticator.cshtml`, `TwoFactorAuthentication.cshtml` and `LoginWith2fa.cshtml`. 

I am not sure how to use them in the register and login process flows. I am following the method described in this link. 

https://www.meziantou.net/implementing-two-factor-authentication-in-an-asp-net-core-application.htm 

As per the link I have downloaded and included `qrcode.js` in the `wwwroot/js` folder and added the following code at the end of the `EnableAuthenticator.cshtml` file.

```lang-cshtml
@section Scripts {
  <partial name="_ValidationScriptsPartial" />
  <script src="~/lib/qrcode/qrcode.min.js"></script>
  <script type="text/javascript">
    new QRCode(document.getElementById("qrCode"),
        {
            text: "@Html.Raw(Model.AuthenticatorUri)",
            width: 200,
            height: 200
        });
  </script>
}

Whenever someone registers to the site with email/password, in the AspNetUsers table, I am setting TwoFactorEnabled = true. While login, I am not sure whether to redirect to LoginWith2fa page or to EnableAuthenticator page.

The following is my code on the login page:

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl ??= Url.Content("~/");

    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();

    if (ModelState.IsValid)
    {
        var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);

        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
                
            string url = $"{stringeGrantsURL}{"?UserToken="}{jwtToken}";

            return Redirect(url);
        }

        if (result.RequiresTwoFactor)
        {
            return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, 
                   RememberMe = Input.RememberMe });
        }

        if (result.IsLockedOut)
        {
            _logger.LogWarning("User account locked out.");
            return RedirectToPage("./Lockout");
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }
    }

    return Page();
}

With the current code the user is sent to the LoginWith2fa page which asks to enter an authenticator code, which I don't know how to generate.

Instead, if I direct the user to the EnableAuthenticator.cshtml page, it simply redirects to the Login.cshtml page. I tried to Google the issue, but most of the samples pertain to ASP.NET Core 5.0 which uses MVC identity and not the .NET Core 6.0 which uses Razor pages.


ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,313 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Ruikai Feng - MSFT 2,536 Reputation points Microsoft Vendor
    2023-05-22T09:14:59.7433333+00:00

    Hi,@Sherpa

    In the AspNetUsers table, I am setting TwoFactorEnabled = true

    You have to follow the steps in this page to configure authenticator app instead of setting TwoFactorEnabled to true directly

    enter image description here

    It would be setted to true automaticlly after you compeleting the steps with the codes:

    await _userManager.SetTwoFactorEnabledAsync(user, true);

    Instead, if I direct the user to the EnableAuthenticator.cshtml page, it simply redirects to the Login.cshtml page.

    EnableAuthenticator.cshtml page is under Manage Folder by default, and Identity added gobal Authorize Attribute to Manage folder ,you can't visit it untill you login successfully(If you've enabled 2FA Authentication,you have to login both with password and the codes provided by Microsoft Authenticator)

    Here's the source codes related:

    public void PostConfigure(string name, RazorPagesOptions options)
            {
                name = name ?? throw new ArgumentNullException(nameof(name));
                options = options ?? throw new ArgumentNullException(nameof(options));
    
                options.Conventions.AuthorizeAreaFolder(IdentityUIDefaultAreaName, "/Account/Manage");
                options.Conventions.AuthorizeAreaPage(IdentityUIDefaultAreaName, "/Account/Logout");
                var convention = new IdentityPageModelConvention<TUser>();
                options.Conventions.AddAreaFolderApplicationModelConvention(
                    IdentityUIDefaultAreaName,
                    "/",
                    pam => convention.Apply(pam));
                options.Conventions.AddAreaFolderApplicationModelConvention(
                    IdentityUIDefaultAreaName,
                    "/Account/Manage",
                    pam => pam.Filters.Add(new ExternalLoginsPageFilter<TUser>()));
            }
    
    
    
    

    You have to login with Email/Password first,enable 2FA authentication following the steps in the page ,when you login next time ,enter the code you get from Microsoft Authenticator


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,

    RuikaiFeng

    0 comments No comments