Search code examples
asp.netasp.net-mvccookiesasp.net-identitytwo-factor-authentication

Can't configure UserCookie to return correct SignInStatus for two factor Authentication


According to MSDN

Both the local log in and social log in check to see if 2FA is enabled. If 2FA is enabled, the SignInManager logon method returns SignInStatus.RequiresVerification, and the user will be redirected to the SendCode action method, where they will have to enter the code to complete the log in sequence. If the user has RememberMe is set on the users local cookie, the SignInManager will return SignInStatus.Success and they will not have to go through 2FA.

I do want the user to be able to use the remember me feature of the application but I can not figure out how to get the cookie to ditch this setting so that the SignInStatus returns RequiresVerifacation. I'm actually not even 100% sure that the cookie is causing it. All I know is that I have enabled TFA and in AspUsers table I can see that TwoFactorEnabled is set to true but the status is always returning as Success.

Here is the controller where I am not getting what I want

   [AllowAnonymous]
    public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
    {  
        var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
        if (loginInfo == null)
        {
            return RedirectToAction("Login");
        }

        // Sign in the user with this external login provider if the user already has a login
        var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
        var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
        switch (result)
        {
            case SignInStatus.Success:
                return RedirectToLocal(returnUrl);
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresVerification:
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
            case SignInStatus.Failure:
            default:
                // If the user does not have an account, then prompt the user to create an account
                ViewBag.ReturnUrl = returnUrl;
                ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
                return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
        }
    }

According to this MSDN page var result should return SignInStatus.RequiresVerification but it returns Success when returning from the OAuth sign in from google or just a regular sign in. The User has their TwoFactorEnabled set to true in the AspUsers Table which is what result is checking according to docs.


Solution

  • The solution to this problem was actually incredibly simple. You just need to KNOW WHAT YOU'RE DOING. ASP Identity is complex and there are a lot of moving parts. If anyone is coming across this post struggling with ASP.NET Identity I would recommend starting here with the Microsoft video series on customizing ASP Identity. There is a lot of info there. The tutorial most helpful for implementing a Google Authenticator style of TFA with QR codes is here