I have implemented the Two Factor Authentication using Asp.NET Identity Framework. I have used the authenticator app mode. Everything works fine in localhost environment but when I deployed it to Azure the final step of Two Factor login part is not working.
Following are the highlights of the code.
Here is how I generate the QR Code Uri.
private async Task<QRCodeDto> GetTwoFactorSetupDataAsync(User user)
{
var operationResult = new QRCodeDto();
var key = await _userManager.GetAuthenticatorKeyAsync(user); // get the key
if (string.IsNullOrEmpty(key))
{
// if no key exists, generate one and persist it
await _userManager.ResetAuthenticatorKeyAsync(user);
// get the key we just created
key = await _userManager.GetAuthenticatorKeyAsync(user);
}
operationResult.Uri = GenerateQrCodeUri(user.Email, key);
operationResult.Key = key;
operationResult.UserId = user.Id;
return operationResult;
}
private string GenerateQrCodeUri(string email, string unformattedKey)
{
const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";
return string.Format(
AuthenticatorUriFormat,
HttpUtility.UrlEncode("ABC Company Name"),
HttpUtility.UrlEncode(email),
unformattedKey);
}
Here is how I verify the authenticator.
public async Task<VerifiedAuthenticatorResultDto> VerifyAuthenticator(VerifyAuthenticatorDto verifyAuthenticator)
{
var operationResult = new VerifiedAuthenticatorResultDto();
var verificationCode = verifyAuthenticator.VerificationCode.Replace(" ", string.Empty).Replace("-", string.Empty);
var user = await _userManager.FindByIdAsync(verifyAuthenticator.UserId.ToString());
if (user != null)
{
var is2FaTokenValid = await _userManager.VerifyTwoFactorTokenAsync(
user, _userManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode);
if (!is2FaTokenValid)
{
operationResult.IsSuccess = false;
operationResult.Message = "Invalid verification code.";
return operationResult;
}
operationResult.IsSuccess = true;
operationResult.Message = "Your authenticator app has been verified";
if (await _userManager.CountRecoveryCodesAsync(user) != 0)
{
return operationResult;
}
else
{
operationResult.RecoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 5);
return operationResult;
}
}
operationResult.IsSuccess = false;
operationResult.Message = "Error verifying authenticator app.";
return operationResult;
}
Up to here it works fine and generates the verification codes as well. But from the following code _signInManager.TwoFactorAuthenticatorSignInAsync() and _signInManager.TwoFactorRecoveryCodeSignInAsync() always fails. Only works in local environment. But not in Azure.
public async Task<TwoFactorSignInResult> TwoFactorLogin(TwoFactorLoginInfo loginInfo)
{
var signInResult = new TwoFactorSignInResult();
UserDto loginUserDto = null;
SignInResult result = null;
// Require the user to have a confirmed email before they can log on.
var user = await _userManager.FindByNameAsync(loginInfo.UserName);
if (user == null)
{
throw new InvalidUserException("Invalid Username.");
}
var authenticatorCode = loginInfo.TwoFactorCode.Replace(" ", string.Empty).Replace("-", string.Empty);
if (!loginInfo.UseRecoveryCode)
{
result = await _signInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, true,
loginInfo.RememberMachine);
}
else
{
result = await _signInManager.TwoFactorRecoveryCodeSignInAsync(authenticatorCode);
}
if (result.Succeeded)
{
signInResult.IsSuccess = true;
signInResult.Message = "Successfully Logged in.";
return signInResult;
}
else
{
throw new InvalidUserException("Invalid token.");
}
}
I have referred this article. Is there any configuration that I have to do in Azure in order for this to work?