The two-step verification is a process where a user enters credentials, and after successful password validation,  receives an OTP (one-time-password) via email or SMS. Then, they enter that OTP in the Two-Step Verification form on our site to log in successfully.

We just have to make one thing clear before we start. Even though many people think that this type of verification is based on something you know (the password) and something you have (device to access Email or SMS), that’s not the case. The ownership of the device is not part of the verification process, on the other hand, the OTP is. Therefore, the OTP is still something we know and it raises some security concerns over the email or SMS. But it is still more secure than a one-time password process.

So, in this article, we are going to learn how to implement a two-step verification process in our project by using ASP.NET Core Identity.

To download the source code for this project, visit the Two-Step Verification with ASP.NET Core Identity repository.

To navigate through the entire series, visit the ASP.NET Core Identity series page.

Let’s look at the basic navigation for this article:

Code Preparation for Two-Step Verification Process

Before we continue, we have to make sure that our user has an email confirmed and a two factor enabled. If we check our only user in the database, we are going to see this is the case:

email confirmed two factor enabled - two-factor verification

If these columns are not set to true (1), you can set them manually.

Now, we can modify the Login action:

So, one of the properties that our result variable contains is RequiresTwoFactor. The PasswordSignInAsync method will set that property to true if the TwoFactorEnabled column for the current user is set to true, and the Succeeded property will be set to false. Therefore, we check if the RequiresTwoFactor property is true and if it is, we redirect a user to a different action with the email, rememberMe and returnUrl parameters.

It is important to mention that as soon as a user gets redirected to the LoginTwoStep action, the new Identity.TwoFactorUserId cookie will be created in our browser. This cookie contains important data about the current user.

Before we create additional actions, let’s create a new model class for the LoginTwoStep action:

Now, we can add two required actions in the Account controller:

Excellent.

We have prepared everything for the two-step verification process. So, let’s implement it.

Implementation of the Two-Step Verification Process

It’s time to modify the GET LoginTwoStep action:

We check if the current user exists in the database. If that’s not the case, we display the error page. But if we find a user, we have to check is there a provider for Email because we want to send our two-step code using an email message. After that check, we just create a token with the GenerateTwoFactorTokenAsync method and send an email message.

Now, let’s just create a view for this action:

This process is quite familiar.

LoginTwoStep POST Implementation

Finally, let’s modify the POST LoginTwoStep action:

So, first, we check the model validity. If it’s valid, we use the GetTwoFactorAuthenticationUserAsync method to get the current user. We do that with the help of our Identity.TwoFactorUserId cookie, created in the first part of this article. This will prove to us that the user indeed went through all the verification steps to get to this point. If we find that user, we use the TwoFactorSignInAsync method to verify the TwoFactorToken value and sign in the user.

If the result is successful, we use the returnUrl parameter to redirect the user. Otherwise, we apply additional checks on the result variable and force appropriate actions.

We don’t want to repeat the same code – that’s why you see the comment in the code sample. But it would be a good practice to extract the code from the Lockout part in the Login action in its own method and then just call that method in the Login and LoginTwoStep actions.

Testing the Entire Process

With everything in place, we can test our functionality.

As soon as we enter valid credentials, we are going to see a new view:

two step view - two-step verification

Then if we check our email:

two-step verification email code

We can see a new token.

Finally, after we enter that token in the input field, we are going to be redirected either to the home view or the protected view. This depends on what we tried to access without authentication:

two step token success

Take notice that the amr property (Authentication Method Reference) now has the mfa value which stands for Multiple-factor Authentication.

Conclusion

So, in this article, we’ve learned how to use a two-step verification process to authenticate a user by using an email provider. But, we don’t have to use only email provider. SMS is also an option that can be used for the process. The same logic applies to the SMS provider.

In the next article, we are going to learn about external accounts and how to handle external identity providers.

So, stay tuned.

If you have enjoyed reading this article and if you would like to receive the notifications about the freshly published .NET Core content we encourage you to subscribe to our blog.