C#, Web

Two-Factor authentication in ASP.NET Identity 3 using TOTP authenticator

5 min read

Two-Factor authentication is becoming more critical especially in business applications where sensitive and/or critical data can be accessed. A business application should communicate on a secure channel (https) and should implement Two-Factor as a minimum for their users especially if they can access the application remotely, which means everywhere. You could obviously skip the Two-Factor authentication when the user is on the intranet. This is not implemented in this article.

What is a Two-Factor authentication?

I will give a brief overview of what Two-Factor authentication actually is. As Joel Franusic described it in his post

Two-Factor Authentication or TFA is a method where your users are required to log in with two “factors”: a password, and a code from a device that they carry with them. That device used to be a special-purpose device, or a token device, but nowadays that device can just as well be a mobile phone.

They are a few patterns for implementing the code generated for the TFA. TOTP (Time-based One-time Password Algorithm) is one and this is the one that is mostly used in Microsoft Authenticator and Google Authenticator application. These TOTP authenticators are based off the RFC6238 standard. To understand how TOTP is implemented, I strongly suggest you go read Joel’s post under the Understand TOTP section and even more the RFC6238 standard.

Identity 3 Two-Factor Implementation

There are a few steps to successfully implement a Two-Factor Provider in Identity 3. You can indeed have many providers and it’s for you to configure them. Identity exposes us through the IdentityBuilder to the AddDefaultTokenProviders method which you can chain onto your AddIdentity call in your startup file. This will give Identity exposure to 3 providers, mainly DataProtectorTokenProvider, PhoneNumberTokenProvider, and EmailTokenProvider.

To create a new provider however, you can follow the approach below

You first need configure a Provider. The provider is the one who will be used to Generate and Validate your Token.

Create a new class that implements IUserTwoFactorTokenProvider<TUser> interface from Identity

Note: my implementation of Identity does not use EF. I am using Dapper as my Backend and implementing my own repositories. The idea however should be the same

As you can see, I created a provider for a software based TOTP Authenticator. I also have a class named TotpSoftwareAuthenticator that I use to generate and validate the token. This class can be a wrapper(adapter) to the real implementation of your TOTP Authenticator that can provide you with more options like create a QRCode to scan, etc. I chose to wrap the real implementation because I don’t need all the noise for Identity; all it needs is to generate and validate the token. Your wrapper could implement an interface like the one below. Obviously, this is a base interface and one could modify the Generate method to accept parameters to pass to the underlying implementation of the Authenticator.

The next step is to assure that your UserStore implements IUserTwoFactorStore<TUser> interface. This will allow the SignInManager to verify if the user has TwoFactor enabled.

The last step is to implement all this beautiful code into your controller.

We need to validate the user’s credentials and checking if the user has TwoFactor enabled. This can be done with the following.

Remember when I said it was important to implement the IUserTwoFactorStore<TUser> interface in your store? This is because the SignInManager will query your store to get the appropriate data. In this case, it will query the store to check if your user has TwoFactor enabled. If so, it will redirect him to another View (Get2FA) for him to enter his token. Once the token is entered, it will be validated and if it matches, it will redirect him to the returnUrl if one is set, otherwise it will redirect him to the Index action of the Index controller.

Here is the full code of all the methods used to process the scenario

There’s a few notes I want to add. This is just a base implementation. Identity will use the Lockout.MaxFailedAccessAttempts option if one tries to signing with an invalid token too many times. There is a case that I did not handle. What if you have more than 1 Token Provider: how do you want to handle this? You could show all the possible Providers to the user and let the user pick which provider he wants to use. In my example, if the user has TotpSoftwareAuthenticator setup in his providers, then I force him to use that one. The former is an idea and an area where you could add some improvement.

The last bit of the puzzle is to tie all this up; we need to configure it in our Startup class.
I changed the default implementation of ConfigureServices(IServiceCollection services) to return Autofac’s Dependency Injection container. Feel free to use which ever one you want.

You need to add in your IdentityOptions class the token provider that you just created. For that you can do the following

Then I had to register my provider in my container

Voilà!

What’s coming in Identity 3?

While writing this post I saw that in version 1.2.0, they implemented another provider AuthenticatorTokenProvider and the IUserAuthenticatorKeyStore interface.

The AuthenticatorTokenProvider class is interesting as this means that a user can use a built-in Token mechanism that is stored in the database.
The IUserAuthenticatorKeyStore interface can be used to implement a store which is used to set and fetch the key. The key is used when validating the token and determining whether the user  can use that provider.

They also provided an abstract class TotpSecurityStampBasedTokenProvider<TUser> which basically would lighten my above provider’s implementation by removing the TotpSoftwareAuthenticator class as it implements RFC6238 and Base32 and is pretty basic. I would have to only override the methods that I see fit.

They also heavy lifted the RFC6238 implementation by providing the Rfc6238AuthenticationService and Base32 implementation to get the code to input in your authenticator (i.e microsoft authenticator, google’s authenticator).

Conclusion

For those wanting to know which underlying Authenticator implementation I used here is the story. At first, I used Brandon Potter’s project that he had done for the Google Authenticator and adapted it to .NETStandard 1.6 so that my library would not have any dependencies on the full .NET Framework. The port to dotnetcore is on its way as there’s a pull that’s awaiting.
Then I realized that in Identity 3 v1.2.0 they had implemented RFC6238 and Base32 and that Brandon Potter’s implementation is just a wrapper on RFC6238 and Base32. Since I wanted to stick with Identity 3 v1.1.0 (updating to 1.2.0 means dependency issues!), I copied the RFC6238 and Base32 classes from Identity 3 v1.2.0 and was able to make a generic TOTP authenticator that works in both Microsoft’s and Google’s authenticator

I’m hoping this little implementation will bring you to implement Two-Factor Authentication in your applications without any fear.