A safe two-factor authentication (2FA) technique called TOTP (Time-based One-Time Password) creates short-lived, one-time codes for user verification. These codes are synchronized with the current time and refresh at predetermined intervals, often every 30 seconds. Compared to static passwords, TOTP improves security by dynamically updating the valid code, which drastically lowers the possibility of unwanted access even in the event that a code is intercepted because it expires fast.
This technique provides a strong barrier against replay attacks and credential theft by guaranteeing that every authentication attempt necessitates a new, time-sensitive code. To create a one-time password, the procedure combines the current time with a shared secret key that is only known by the user and the server. In addition to the user’s usual login information, this password is then used to confirm the user’s identity. Because TOTP effectively increases security without being unduly complex for users, it is frequently utilized in a variety of applications, including mobile banking and online account security.
Why MFA?
Multi-Factor Authentication (MFA) significantly enhances application security by requiring users to verify their identity using multiple methods. While traditional authentication uses only a username and password, MFA adds a second layer — typically a time-based one-time password (TOTP), which expires every 30 seconds.
This article walks you through implementing TOTP-based MFA in a real-world ASP.NET Core setup consisting of,
- A Web API project to handle backend authentication logic.
- A MVC UI project to handle frontend interaction with the user.
Project Architecture
Our application consists of two projects.
totp_dotnet_api– ASP.NET Core Web API
- Contains TOTP Controller having login, setup and verify three endpoints.
- One TotpService class for logic handling
totp_dotnet_mvc– ASP.NET Core MVC
Contains login and setup TOTP pages with controller.
Folder Structure
Now let’s create endpoints in the Web API project. The Web API project provides three key endpoints to manage user login and TOTP-based multi-factor authentication. Each of these plays a specific role in the authentication flow: login, MFA setup, and verification.
[HttpPost("login")]
public IActionResult Login([FromBody] LoginRequest request)
{
if (request == null)
return BadRequest("Invalid request");
var response = _totpService.Login(request.Username, request.Password);
return Ok(response);
}
[HttpPost("setup")]
public IActionResult SetupTotp([FromBody] TotpSetupRequest request)
{
if (request == null)
return BadRequest("Invalid request");
var response = _totpService.SetupTotp(request.Username);
return Ok(response);
}
[HttpPost("verify")]
public IActionResult VerifyTotp([FromBody] TotpVerificationRequest request)
{
if (request == null)
return BadRequest("Invalid request");
var response = _totpService.VerifyTotp(request.Username, request.Code);
return Ok(response);
}
In the code given above, we created endpoints for login, setup, and verification. Now lets create one TotpService.cs class inside Services folder as given in the folder structure. This class will contain different methods calling from controller. This service is responsible for all the logic behind.
- User login validation
- Setting up TOTP
- Verifying TOTP codes
In this example, there’s no real database — you’re using static dictionaries (_userPasswords and _userSecrets) to simulate user data and their MFA secrets.
Method: Login
- Tries to fetch the user’s TOTP secret.
- Validates username and password from _userPasswords.
- If valid, assumes TOTP is not yet enabled and:
- Calls SetupTotp() to provide the TOTP QR code and secret.
- Returns a LoginResponse indicating success and includes the QR code URL + secret.
Note. In a production app, you’d only setup TOTP during registration or profile settings, not on every login.
Method: SetupTotp
- Retrieves the user’s existing TOTP secret from _userSecrets.
- Prepares a LoginResponse:
- IsTotpEnabled = true
- Generates a TOTP-compatible QR Code URI
- Converts the QR code into a Base64 string so it can be embedded directly in an <img> tag in your HTML page.
In real scenarios, you’d generate a new key here and persist it securely. You’re currently using a predefined one.
Method: VerifyTotp
- Fetches the Base32 secret for the user.
- Uses the Otp.NET library to:
- Decode the Base32 secret.
- Create a Totp instance.
- Verify the user-supplied code against the current TOTP window (±1 interval).
- Returns a success/failure response.
MVC UI Integration for TOTP MFA
Now that we’ve built the backend logic and API endpoints for user login and TOTP verification, it’s time to integrate a simple ASP.NET Core MVC frontend. The UI will guide the user through the login and 2FA setup process. The home page serves as the entry point. It provides two options.
- Login – Triggers the standard login flow.
- Enable 2FA – Directly initiates the TOTP setup process (for users who want to secure their account with MFA proactively).
When the user clicks the Login button.
- They are redirected to the login form where they enter: Username, Password
- On submission, the Login API is called via HttpClient.
- The API response decides the next step:
- If 2FA is enabled, the user is redirected to the TOTP Verification screen.
- If 2FA is not enabled, the app initiates the TOTP Setup screen so the user can configure MFA.
Note: As of now in this demo you will see both the screen since we are not using database to store ‘IsEnabled’ key for the users.
Enable 2FA (SetupTotp.cshtml)
- When a user clicks Enable 2FA on the homepage.
- The Setup API is triggered using the logged-in user’s username.
- The QR code is returned from the API as a Base64 image.
- The user is shown the QR code on the screen and asked to scan it using an authenticator app.
- A text field allows them to enter the 6-digit TOTP from their app.
TOTP Verification (VerifyTotp.cshtml)
If the user logged in and already has MFA enabled, they are immediately redirected here to complete the second step of authentication.
- The user enters the 6-digit code generated by their authenticator app.
- The Verify API is called.
- If verification is successful:
- The user is authenticated and redirected to the protected area.
- The JWT token is stored in session or cookies.
- If it fails: Show an error message and allow retry.
Security Considerations
- Secret Storage
- Always encrypt TOTP secrets in database
- Never log or display the secret after initial setup
- Rate Limiting
- Implement rate limiting on TOTP verification attempts
- Exponential delays after failed attempts
- Time Synchronization
- Ensure server time is synchronized with NTP
- Allow small window for clock drift (±1-2 time steps)
- Session Management
- Don’t persist 2FA state in cookies
- Use server-side session storage
Conclusion
Implementing TOTP-based MFA in .NET Core provides a robust security layer for your applications. This implementation supports both web and API authentication flows, giving users flexibility while maintaining security. The solution can be extended with additional features like SMS fallback or hardware token support.
We covered,
- Backend Setup: A clean Web API using .NET Core that handles login, TOTP setup, and verification.
- Security Logic: How to generate and verify TOTP codes using static secrets and the Otp.NET library.
- Frontend UI (MVC): A user-friendly interface that enables login, QR code showing, and TOTP verification using views and form-based workflows.
Best ASP.NET Core 8.0.11 Hosting
The feature and reliability are the most important things when choosing a good ASP.NET Core 8.0.11 hosting. HostForLIFE is the leading provider of Windows hosting and affordable ASP.NET Core , their servers are optimized for PHP web applications such as the latest ASP.NET Core 8.0.11 version. The performance and the uptime of the ASP.NET Core hosting service are excellent, and the features of the web hosting plan are even greater than what many hosting providers ask you to pay for. At HostForLIFEASP.NET, customers can also experience fast ASP.NET Core hosting. The company invested a lot of money to ensure the best and fastest performance of the datacenters, servers, network and other facilities. Its data centers are equipped with top equipment like cooling system, fire detection, high-speed Internet connection, and so on. That is why HostForLIFEASP.NET guarantees 99.9% uptime for ASP.NET Core . And the engineers do regular maintenance and monitoring works to assure its ASP.NET Core hosting are security and always up.