Account lockout is an important security feature that protects user accounts from brute-force attacks and repeated unauthorized login attempts. Without account lockout, an attacker could try thousands of password combinations until they eventually guess the correct one.
Most modern systems (Google, Microsoft, GitHub, banking apps) use account lockout to:
In this article, you will learn how to build a complete Account Lockout System using:
This article uses simple language and includes complete practical code for beginners.
What You Will Build
By the end of this tutorial, you will implement:
Tracking failed login attempts in the database
Automatic lockout after a certain number of failed attempts
Auto unlock after a specified time (e.g., 5 or 15 minutes)
Error messages guiding the user
Angular UI updates
Backend checks to enforce lockout
Optional features like permanent lockout or admin unlock
Why Account Lockout Matters
Attackers use automated tools to attempt thousands of password guesses per minute. Without account lockout, they could easily breach weak or reused passwords.
Account lockout helps by:
Limiting the number of attempts
Slowing down attackers
Preventing automated scripts
Notifying users when suspicious activity happens
It is a proven layer of security and is recommended in OWASP and NIST guidelines.
System Architecture Overview
The system will use these fields in the User table:
Flow
User enters email and password
Backend checks if the account is locked
If locked, deny login
If credentials are wrong, increase FailedLoginAttempts
If attempts reach the limit, set lockout time (example: 5 minutes)
If credentials are correct, reset FailedLoginAttempts
Allow login
This protects your system from brute-force attacks.
Part 1: Backend Implementation (ASP.NET Core)
Step 1: Update User Model
File: Models/User.cs
public class User
{
public int Id { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public string PasswordHash { get; set; }
public int FailedLoginAttempts { get; set; } = 0;
public DateTime? LockoutEnd { get; set; }
}
Step 2: Account Lockout Configuration
Define your lockout policy:
public class LockoutSettings
{
public const int MaxFailedAttempts = 5;
public const int LockoutMinutes = 5;
}
Step 3: Modify Login Endpoint
File: AuthController.cs
[HttpPost("login")]
public async Task<IActionResult> Login(LoginDto request)
{
var user = await _context.Users.FirstOrDefaultAsync(u => u.Email == request.Email);
if (user == null)
return BadRequest(new { Message = "Invalid email or password" });
// Check if locked
if (user.LockoutEnd.HasValue && user.LockoutEnd.Value > DateTime.Now)
{
var remaining = user.LockoutEnd.Value - DateTime.Now;
return BadRequest(new
{
Message = $"Account locked. Try again in {remaining.Minutes} minutes and {remaining.Seconds} seconds."
});
}
// Check password
if (!BCrypt.Net.BCrypt.Verify(request.Password, user.PasswordHash))
{
user.FailedLoginAttempts++;
if (user.FailedLoginAttempts >= LockoutSettings.MaxFailedAttempts)
{
user.LockoutEnd = DateTime.Now.AddMinutes(LockoutSettings.LockoutMinutes);
await _context.SaveChangesAsync();
return BadRequest(new
{
Message = $"Account locked due to many failed attempts. Try again after {LockoutSettings.LockoutMinutes} minutes."
});
}
await _context.SaveChangesAsync();
return BadRequest(new
{
Message = $"Invalid password. Attempts remaining: {LockoutSettings.MaxFailedAttempts - user.FailedLoginAttempts}"
});
}
// Successful login: reset attempts
user.FailedLoginAttempts = 0;
user.LockoutEnd = null;
await _context.SaveChangesAsync();
var token = _jwtService.GenerateToken(user);
return Ok(new { Token = token });
}
What this code does
Checks if the account is currently locked
Locks the user if failed attempts reach the limit
Shows remaining attempts
Unlocks automatically after time expires
Resets attempts on successful login
Part 2: SQL Table Update
Update your Users table by adding the new fields:
ALTER TABLE Users
ADD FailedLoginAttempts INT DEFAULT 0;
ALTER TABLE Users
ADD LockoutEnd DATETIME NULL;
Part 3: Frontend Implementation (Angular)
Step 1: Modify Login Component
login.component.ts
submit() {
this.auth.login(this.model).subscribe({
next: res => {
this.auth.saveToken(res.token);
this.router.navigate(['/dashboard']);
},
error: err => {
this.message = err.error.message;
}
});
}
Step 2: Display Messages in Template
login.component.html
<h2>Login</h2>
<input type="text" [(ngModel)]="model.email" placeholder="Email" />
<input type="password" [(ngModel)]="model.password" placeholder="Password" />
<button (click)="submit()">Login</button>
<p style="color: red">{{ message }}</p>
Angular will now show:
Wrong password attempts
Remaining attempts
Account locked message
Part 4: How the Lockout System Works
Example policy
5 failed attempts allowed
After 5 wrong attempts → lock for 5 minutes
After 5 minutes → user can login again
On correct login → attempts reset to zero
Example scenario
User enters wrong password:
After lockout ends:
Part 5: Additional Security Improvements
You can enhance the system by adding:
1. Permanent Lockout After Multiple Lockouts
If user triggers 3 lockouts → Permanently lock until admin resets.
2. Email Notification on Lockout
Send alert:
"Your account was locked due to suspicious activity."
3. IP-Based Lockout
Prevent brute-force attacks from a specific IP.
4. CAPTCHA Before Login
After 3 failures → show CAPTCHA (e.g., Google reCAPTCHA).
5. Log Every Failed Attempt
Store IP, browser, timestamp in a separate table.
6. Admin Dashboard to Unlock Users
Allow support staff to manually reset lockout.
If you want any of these features, I can create a separate article with full code.
Part 6: Testing the Lockout System
Step 1
Try logging in with wrong password 5 times.
Expected behavior:
Step 2
Try logging in during the lockout time.
Expected behavior:
Step 3
Wait for lockout duration, then login with correct password.
Expected behavior:
Conclusion
You have now built a complete, secure Account Lockout System using:
Account lockout is a powerful protection against brute-force and automated login attacks. Every serious application should implement it to improve security and protect user accounts.