Auth Shield
Auth Shield protects your login endpoints from brute-force attacks and credential stuffing. When enabled, it monitors authentication attempts per IP, automatically locks out offending clients after repeated failures, and emits threat events into the Sentinel pipeline.
How It Differs from Rate Limiting
Configuration
Auth Shield is configured through the AuthShieldConfig section of sentinel.Config. All fields have sensible defaults except LoginRoute, which must match your actual login endpoint path.
| Field | Type | Default | Description |
|---|---|---|---|
Enabled | bool | false | Enables the Auth Shield middleware. |
LoginRoute | string | "" | The exact path of your login endpoint (e.g., /api/login). Must match the route registered in Gin. |
MaxFailedAttempts | int | 5 | Number of failed login attempts within the lockout window before the IP is locked out. |
LockoutDuration | time.Duration | 15 * time.Minute | How long an IP remains locked out after exceeding MaxFailedAttempts. Also used as the sliding window for counting failures. |
CredentialStuffingDetection | bool | false | When enabled, detects a single IP trying many different usernames (more than 10 unique usernames within the window). |
BruteForceDetection | bool | false | When enabled, detects repeated password guessing against the same username. |
How It Works
Auth Shield registers as Gin middleware and intercepts only POST requests to the configured LoginRoute. All other routes and HTTP methods pass through untouched. The flow is:
- Pre-check — Before your login handler runs, Auth Shield checks if the client IP is currently locked out. If it is, the request is immediately rejected with a
429 Too Many Requestsresponse. - Passthrough — If the IP is not locked, the request proceeds to your login handler as normal.
- Observe response — After your handler responds, Auth Shield inspects the HTTP status code:
- 2xx — Successful login. The failure counter for that IP (and username, if provided) is reset to zero.
- 4xx — Failed login. The failure is recorded with a timestamp.
- Lockout — If the number of failures from an IP within the
LockoutDurationwindow reachesMaxFailedAttempts, the IP is locked out for the fullLockoutDuration.
LoginRoute Must Match Exactly
LoginRoute must be the exact path string of your login handler (e.g., /api/login). It is compared against c.Request.URL.Path. If it does not match, Auth Shield will not intercept the request and no failures will be tracked.Example Configuration
A typical production setup with 5 allowed attempts and a 15-minute lockout:
1package main23import (4 "time"56 sentinel "github.com/MUKE-coder/sentinel"7 "github.com/gin-gonic/gin"8)910func main() {11 r := gin.Default()1213 sentinel.Mount(r, nil, sentinel.Config{14 AuthShield: sentinel.AuthShieldConfig{15 Enabled: true,16 LoginRoute: "/api/login",17 MaxFailedAttempts: 5,18 LockoutDuration: 15 * time.Minute,19 CredentialStuffingDetection: true,20 BruteForceDetection: true,21 },22 })2324 r.POST("/api/login", func(c *gin.Context) {25 // Your login logic here26 username := c.PostForm("username")27 password := c.PostForm("password")2829 // Optionally set the username so Auth Shield can track per-user failures30 c.Set("sentinel_username", username)3132 if username == "admin" && password == "correct-password" {33 c.JSON(200, gin.H{"token": "jwt-token-here"})34 } else {35 c.JSON(401, gin.H{"error": "Invalid credentials"})36 }37 })3839 r.Run(":8080")40}
Username Tracking
c.Set("sentinel_username", username) in your login handler before writing the response. Auth Shield reads this value from the Gin context. If not set, only IP-based tracking is used.What Gets Tracked
Auth Shield determines success or failure based on the HTTP status code returned by your login handler:
| Status Code | Interpretation | Action |
|---|---|---|
200-299 | Successful login | Reset all failure counters for the IP and username. |
400-499 | Failed login | Increment the failure counter. Lock the IP if MaxFailedAttempts is reached. |
500+ | Server error | Ignored. Server errors are not counted as failed login attempts. |
Failure timestamps older than LockoutDuration are automatically pruned from the sliding window, so a slow trickle of failures over a long period will not trigger a lockout.
Design Your Login Handler Accordingly
401 for invalid credentials and a 200 for successful logins. Avoid returning 200 with an error in the body, as Auth Shield will treat it as a success and reset the counter.Lockout Response
When a locked-out IP attempts to access the login route, Auth Shield returns the following response without invoking your login handler:
{"error": "Too many failed login attempts. Please try again later.","code": "AUTH_SHIELD_LOCKED"}
Events
Auth Shield emits threat events into the Sentinel pipeline whenever a lockout is triggered or credential stuffing is detected. These events flow through the same pipeline as WAF and anomaly events, meaning they are:
- Stored in the configured storage backend
- Visible in the dashboard Threats page
- Eligible for alerting (Slack, email, webhook) based on severity
- Available for AI analysis if an AI provider is configured
Threat Event Types
| Threat Type | Trigger | Severity |
|---|---|---|
BruteForce | IP locked out after exceeding MaxFailedAttempts | High |
CredentialStuffing | Single IP tries more than 10 different usernames within the window | High |
Each event includes the offending IP, the login route path, a confidence score of 90, and evidence detailing the specific detection pattern.
Testing
You can verify Auth Shield is working by sending failed login requests and observing the lockout behavior. The following example assumes the default configuration with 5 max attempts.
Trigger a Lockout
# Send 5 failed login attempts (invalid credentials)for i in $(seq 1 5); doecho "Attempt $i:"curl -s -o /dev/null -w "HTTP %{http_code}" \-X POST http://localhost:8080/api/login \-d "username=admin&password=wrong"echo ""done# Attempt 1-5: HTTP 401 (failed login, counter incrementing)# After 5 failures, the IP is now locked out.
Verify the Lockout
# The 6th attempt should return 429 (locked out)curl -s -w "\nHTTP %{http_code}\n" \-X POST http://localhost:8080/api/login \-d "username=admin&password=wrong"# Expected output:# {"error":"Too many failed login attempts. Please try again later.","code":"AUTH_SHIELD_LOCKED"}# HTTP 429
Verify Successful Login Still Works (from a different IP)
# Even correct credentials from the locked IP are rejectedcurl -s -w "\nHTTP %{http_code}\n" \-X POST http://localhost:8080/api/login \-d "username=admin&password=correct-password"# HTTP 429 (still locked — must wait for LockoutDuration to expire)
Testing Locally
127.0.0.1 or ::1, so they share a single IP counter. To test with different IPs, use the X-Forwarded-For header if your setup supports it, or test from different machines.Dashboard
Auth Shield events appear in the Sentinel dashboard on the Threats page. Each event includes:
- Threat type displayed as
BruteForceorCredentialStuffing - The offending IP address
- Timestamp of when the lockout was triggered
- Severity level (High)
- Evidence showing the detection pattern and location (
auth_shield)
You can filter the Threats page by type to isolate brute-force and credential stuffing events. If alerting is configured with a minimum severity of High or lower, these events will also trigger Slack, email, or webhook notifications.
Combining with Rate Limiting
Auth Shield and rate limiting are complementary. A recommended pattern is to use both:
1sentinel.Config{2 // Auth Shield: locks out IPs after failed login attempts3 AuthShield: sentinel.AuthShieldConfig{4 Enabled: true,5 LoginRoute: "/api/login",6 MaxFailedAttempts: 5,7 LockoutDuration: 15 * time.Minute,8 CredentialStuffingDetection: true,9 BruteForceDetection: true,10 },1112 // Rate Limiting: caps overall request volume to the login route13 RateLimit: sentinel.RateLimitConfig{14 Enabled: true,15 ByRoute: map[string]sentinel.Limit{16 "/api/login": {Requests: 10, Window: 15 * time.Minute},17 },18 },19}
In this setup, rate limiting prevents any IP from making more than 10 requests to the login route in 15 minutes (regardless of success or failure), while Auth Shield specifically tracks authentication failures and locks out after 5 failed attempts.
Next Steps
- Configuration Reference — Full list of all configuration options
- Rate Limiting — Per-IP, per-user, and per-route rate limits
- Anomaly Detection — Behavioral analysis including credential stuffing patterns
- Alerting — Get notified when brute-force attacks are detected
- Dashboard — Explore the Threats page and other security views