ASP.NET Core  

Implementing Two-Factor Authentication with Angular and ASP.NET Core

Security is one of the most critical concerns in modern web applications. While traditional username and password authentication remains common, it is increasingly insufficient against advanced cyber threats. Two-Factor Authentication (2FA) adds an additional security layer, making it much harder for attackers to compromise accounts.

In this article, we will explore how to implement Two-Factor Authentication (2FA) in a web application using Angular on the frontend and ASP.NET Core on the backend. We will focus on real-world best practices, technical accuracy, and maintainable architecture.

Table of Contents

  1. Introduction to Two-Factor Authentication

  2. Types of Two-Factor Authentication

  3. System Architecture Overview

  4. Setting Up ASP.NET Core Backend

  5. Implementing 2FA in ASP.NET Core Identity

  6. Setting Up Angular Frontend

  7. Building the 2FA Workflow in Angular

  8. Integrating with Email and SMS Providers

  9. Best Practices for Security

  10. Testing and Deployment

  11. Conclusion

1. Introduction to Two-Factor Authentication

Two-Factor Authentication (2FA) enhances account security by requiring two forms of verification:

  1. Something the user knows: Password or PIN.

  2. Something the user has: One-time code via SMS, email, or authenticator app.

Even if an attacker obtains the password, 2FA prevents unauthorized access. In modern enterprise applications, 2FA is often mandatory for sensitive operations like financial transactions, administrative access, or personal data changes.

2. Types of Two-Factor Authentication

Common 2FA methods include:

  • TOTP (Time-Based One-Time Password): Generated by apps like Google Authenticator or Microsoft Authenticator.

  • SMS/Email OTP: One-time code sent via SMS or email.

  • Push Notifications: Approve login from a registered device.

In this article, we will focus on TOTP 2FA using Angular and ASP.NET Core Identity, which is secure, reliable, and does not depend on mobile network availability.

3. System Architecture Overview

A secure 2FA implementation requires a clear separation between frontend and backend responsibilities:

Backend (ASP.NET Core)

  • ASP.NET Core 8+ with Identity

  • Entity Framework Core for database management

  • TOTP generation and verification logic

  • Email/SMS service for OTP delivery

Frontend (Angular)

  • Angular 16+ with Reactive Forms

  • Angular Material for UI components

  • HTTP interceptors for authentication headers

  • Token-based authentication (JWT)

Communication

  • Secure REST APIs for login, 2FA setup, verification, and token issuance

  • HTTPS enforced for all communications

This architecture ensures security, scalability, and maintainability.

4. Setting Up ASP.NET Core Backend

Create a new ASP.NET Core Web API project:

dotnet new webapi -n TwoFactorAuthAPI
cd TwoFactorAuthAPI

Add ASP.NET Core Identity and Entity Framework Core:

dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer

Configure Identity in Program.cs

builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

builder.Services.AddAuthentication();

5. Implementing 2FA in ASP.NET Core Identity

ASP.NET Core Identity provides built-in support for TOTP-based 2FA.

a. Enabling 2FA for a User

var user = await _userManager.FindByEmailAsync(email);
var is2faEnabled = await _userManager.GetTwoFactorEnabledAsync(user);

b. Generating a TOTP Secret

var unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);
if (string.IsNullOrEmpty(unformattedKey))
{
    await _userManager.ResetAuthenticatorKeyAsync(user);
    unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);
}

This key is displayed as a QR code in the Angular frontend for the user to scan in Google Authenticator or similar apps.

c. Verifying the TOTP Code

var isValid = await _userManager.VerifyTwoFactorTokenAsync(
    user, _userManager.Options.Tokens.AuthenticatorTokenProvider, token);

6. Setting Up Angular Frontend

Create an Angular project with routing and SCSS:

ng new two-factor-auth --routing --style=scss
cd two-factor-auth
ng add @angular/material

Add a service to handle authentication:

@Injectable({ providedIn: 'root' })
export class AuthService {
  constructor(private http: HttpClient) {}

  login(credentials: { email: string; password: string }) {
    return this.http.post('/api/auth/login', credentials);
  }

  verify2FA(token: string) {
    return this.http.post('/api/auth/verify2fa', { token });
  }
}

7. Building the 2FA Workflow in Angular

A typical 2FA login flow:

  1. User submits email and password.

  2. Backend validates credentials.

  3. If 2FA is enabled, backend returns a 2FA required response.

  4. User enters the TOTP code from the authenticator app.

  5. Backend verifies the TOTP and issues JWT access token.

a. Angular Reactive Form for 2FA

this.twoFAForm = this.fb.group({
  token: ['', [Validators.required, Validators.minLength(6), Validators.maxLength(6)]]
});

b. Angular Component Logic

submit2FA() {
  if (this.twoFAForm.invalid) return;

  this.authService.verify2FA(this.twoFAForm.value.token)
    .subscribe({
      next: (res: any) => {
        localStorage.setItem('token', res.token);
        this.router.navigate(['/dashboard']);
      },
      error: (err) => this.snackBar.open('Invalid 2FA code', 'Close', { duration: 3000 })
    });
}

c. QR Code Display for Setup

Use ngx-qrcode library:

npm install ngx-qrcode
<ngx-qrcode [qrc-value]="qrCodeUrl"></ngx-qrcode>

The QR code URL is generated from the backend TOTP secret.

8. Integrating with Email and SMS Providers

Although TOTP is primary, email or SMS OTP can be used as backup.

a. Email OTP Example with SMTP

var message = new MailMessage();
message.To.Add(user.Email);
message.Subject = "Your OTP Code";
message.Body = $"Your OTP is {otpCode}";
smtpClient.Send(message);

b. SMS OTP Example

Use services like Twilio or AWS SNS:

var message = await _twilioClient.Messages.CreateAsync(
    body: $"Your OTP is {otpCode}",
    from: new Twilio.Types.PhoneNumber(twilioNumber),
    to: new Twilio.Types.PhoneNumber(user.PhoneNumber)
);

9. Best Practices for Security

  1. Use HTTPS for all API endpoints.

  2. Enforce strong passwords with Identity options.

  3. Lockout users after multiple failed attempts.

  4. Rate-limit 2FA attempts to prevent brute-force attacks.

  5. Secure storage of TOTP secrets; avoid plain text.

  6. Audit logs for 2FA setup and verification events.

  7. JWT expiration and refresh tokens for session management.

10. Testing and Deployment

Testing

  • Unit tests for authentication services in Angular and ASP.NET Core.

  • Integration tests for 2FA verification flow.

  • Manual tests with Google Authenticator or Authy.

Deployment

  • Use Docker for containerization.

  • Enable HTTPS in production.

  • Ensure database connection strings and secrets are stored securely (Azure Key Vault, AWS Secrets Manager, or environment variables).

Conclusion

Two-Factor Authentication significantly improves application security by adding a second verification step. Using Angular and ASP.NET Core Identity, developers can implement a robust, production-ready 2FA system that supports TOTP, email, and SMS-based OTPs.

Key takeaways

  • 2FA enhances security even if passwords are compromised.

  • Angular provides a responsive and user-friendly interface for setup and verification.

  • ASP.NET Core Identity simplifies TOTP generation and verification.

  • Following best practices ensures scalability, maintainability, and security.

By implementing 2FA correctly, you protect both your users and your application from common security threats.