Overview
The AuthService implements defense-in-depth security, with multiple layers of protection against common authentication attacks. Every design decision prioritizes security over convenience.This service follows OWASP guidelines and NIST standards for authentication security.
Password Security
PBKDF2 Password Hashing
Passwords are hashed using PBKDF2-HMAC-SHA512, the NIST-recommended algorithm for password storage. Implementation (PasswordService.cs:17-37):600,000 Iterations
OWASP 2024 recommendation for PBKDF2-SHA512Makes brute-force attacks computationally expensive. Each password attempt takes ~100ms to verify.At 600k iterations, cracking a 10-character password would take centuries with current hardware.
SHA-512 Algorithm
512-bit output provides collision resistanceStronger than SHA-256, recommended by NIST SP 800-132 for password hashing.More resistant to GPU/ASIC attacks than MD5 or SHA-1.
32-byte Random Salt
Unique per password prevents rainbow table attacksGenerated using cryptographically secure RNG (PasswordService.cs:26).Stored alongside hash in format:
iterations:salt:hash64-byte Hash Output
512-bit hash maximizes securityLonger than typical 256-bit hashes, providing extra collision resistance.Hash + salt together make precomputed attacks infeasible.
Click to see comparison
Click to see comparison
| Algorithm | Pros | Cons | AuthService Choice |
|---|---|---|---|
| PBKDF2 | NIST-approved, built into .NET, configurable iterations | Slightly more vulnerable to GPU attacks | ✅ Used here |
| bcrypt | Industry standard, GPU-resistant | Fixed cost factor (2^n), limited to 72-byte passwords | ❌ Less control |
| Argon2 | Winner of Password Hashing Competition, memory-hard | Not in .NET Core, requires native library | ❌ External dependency |
Timing Attack Prevention
Password verification uses constant-time comparison to prevent timing attacks (PasswordService.cs:57-58):Without constant-time comparison
A naive comparison like
actualHash == expectedHash exits early on the first mismatched byte.Attacker can measure response times:- Fast response → first byte wrong
- Slower response → more bytes correct
Account Lockout Protection
Brute-Force Prevention
After 5 failed login attempts, accounts are locked for 15 minutes (AuthService.cs:25-27):IsLockedOut method (User.cs:20-21):
- Credential stuffing: Limits attacker to 5 attempts per account
- Brute-force: Makes large-scale attacks impractical (15min × attempts = weeks)
- Dictionary attacks: Rate-limits password guessing
Lockout Reset on Success
When a user logs in successfully, the lockout counter is reset (AuthService.cs:102-105):Information Disclosure Prevention
Generic Error Messages
The service returns identical error messages for different failure scenarios to prevent username enumeration. Email doesn’t exist (AuthService.cs:72-76):- Whether an email is registered
- Whether the password is correct for an existing account
- Whether an account is active or disabled
Centralized Error Handling
All exceptions are caught and normalized by middleware (ExceptionHandlingMiddleware.cs:29-38):- Consistent error format across all endpoints
- No stack traces leaked in production
- Internal errors return generic “500” message
- Security-relevant errors are logged (ExceptionHandlingMiddleware.cs:40-41)
Token Security
Refresh Token Rotation
See the dedicated Token Rotation page for details. Key points:- Single-use tokens: Each refresh invalidates the previous token
- Reuse detection: Using an old token triggers security response
- Family revocation: All descendant tokens are invalidated on breach
Cryptographically Secure Token Generation
Refresh tokens are generated usingRandomNumberGenerator (TokenService.cs:62-66):
- 64 bytes of entropy (512 bits) makes tokens unguessable
- Base64 encoding for safe transport in JSON/HTTP
- Cryptographically secure RNG (not pseudo-random)
JWT Security
Access tokens are signed JWTs using HMAC-SHA256 (TokenService.cs:26-56):- HMAC-SHA256 signature: Prevents token tampering
- Issuer validation: Rejects tokens from other sources
- Audience validation: Ensures tokens are for this service
- Expiry validation: Rejects expired tokens (15 minutes)
- Not-before validation: Rejects tokens used too early
IP Address Tracking
Forensic Data Collection
The service tracks IP addresses for all authentication events (AuthController.cs:81-84):- Registration:
CreateRefreshToken(ipAddress)(AuthService.cs:190) - Login:
CreateRefreshToken(ipAddress)(AuthService.cs:190) - Token refresh:
CreatedByIpon new token (RefreshToken.cs:12) - Token revocation:
RevokedByIp(AuthService.cs:140, 164)
- Detect logins from unusual locations
- Correlate token reuse attacks with IP addresses
- Forensic analysis after breach detection
- Identify compromised devices
IP addresses are not used for authorization—only for logging and forensics. Authorization is purely token-based.
Account Status Controls
Active/Inactive Flag
Accounts can be disabled without deletion (User.cs:14):- Temporarily disable suspicious accounts
- Soft-delete users (preserve data, revoke access)
- Implement “account suspension” feature
- Comply with GDPR “right to erasure” (mark inactive, delete later)
Activity Timestamps
User entity tracks important dates (User.cs:15-16):LastLoginAt is updated on successful login (AuthService.cs:105):
- Identify dormant accounts (no login in 90+ days)
- Show “last login” to users for security awareness
- Detect compromised accounts (sudden activity after long dormancy)
- Compliance reporting (active user counts)
Token Lifecycle Management
Automatic Token Cleanup
Old tokens are automatically purged to prevent database bloat (AuthService.cs:224-233):- Active tokens: Never deleted (needed for auth)
- Inactive tokens < 30 days: Kept (forensics)
- Inactive tokens > 30 days: Deleted (space management)
Revocation Tracking
When tokens are revoked, metadata is preserved (RefreshToken.cs:15-18):"Rotación normal"- Token rotated during refresh (AuthService.cs:142)"Token reuse detectado"- Security event triggered (AuthService.cs:129, 247)"Revocación manual"- User logged out (AuthService.cs:165)"User logout"- Explicit logout by user (AuthController.cs:63)
Input Validation
Request DTOs
All inputs are validated using data annotations (AuthDTOs.cs:5-23):- Email format:
[EmailAddress]ensures valid email syntax - Password length: 8-128 characters (prevents empty and overly long passwords)
- Username length: Max 100 characters (prevents buffer attacks)
- Required fields: All fields are mandatory
Email Normalization
Emails are normalized to lowercase to prevent duplicate accounts (AuthService.cs:47, 55, 70):John@Example.comandjohn@example.comare treated as the same account- No duplicate registrations due to case differences
- Consistent lookup behavior
Logging and Monitoring
Security Event Logging
Critical security events are logged (AuthService.cs:23):-
Successful registration (AuthService.cs:62):
-
Account lockout (AuthService.cs:95):
-
Successful login (AuthService.cs:109):
-
Token reuse attack (AuthService.cs:127-128):
-
Token revocation (AuthService.cs:169):
-
Unhandled exceptions (ExceptionHandlingMiddleware.cs:40-41):
Information: Normal operations (registration, login, revocation)Warning: Security events (lockout, token reuse)Error: System failures (unhandled exceptions)
What NOT to Log
Database Security
No Plaintext Secrets
Passwords are never stored in plaintext. Only PBKDF2 hashes are persisted (User.cs:8):Token Storage
Refresh tokens are stored verbatim in the database (RefreshToken.cs:7):- Tokens are cryptographically random (512 bits)
- They’re single-use (rotation)
- Database access requires authentication
- Tokens have limited lifetime (7 days)
For ultra-high-security environments, consider hashing refresh tokens before storage. Trade-off: adds complexity and one additional DB query per refresh.
Security Headers
While not explicitly shown in the code, production deployments should add security headers:Security Checklist
Password Security
✅ PBKDF2-SHA512 with 600k iterations
✅ 32-byte random salt per password
✅ Constant-time comparison
✅ Minimum 8-character requirement
Authentication Security
✅ Account lockout after 5 failed attempts
✅ Generic error messages (no enumeration)
✅ JWT signature validation
✅ Token expiration enforcement
Token Security
✅ Refresh token rotation
✅ Reuse attack detection
✅ Cryptographically secure generation
✅ IP address tracking
Threat Model Coverage
| Attack Vector | Mitigation | Implementation |
|---|---|---|
| Brute-force login | Account lockout (5 attempts, 15min) | AuthService.cs:88-96 |
| Credential stuffing | Rate limiting via lockout | AuthService.cs:88-96 |
| Rainbow table | Unique salt per password | PasswordService.cs:26 |
| Timing attack | Constant-time comparison | PasswordService.cs:58 |
| Token theft | Rotation + reuse detection | AuthService.cs:114-152 |
| Token tampering | HMAC-SHA256 signature | TokenService.cs:31 |
| Username enumeration | Generic error messages | AuthService.cs:72-76 |
| Session hijacking | Short-lived access tokens (15min) | TokenService.cs:44 |
| XSS token theft | HttpOnly cookies (client responsibility) | N/A |
| CSRF | Token-based auth (no cookies for auth) | N/A |
| SQL injection | Entity Framework parameterization | Entire codebase |
| Replay attacks | Unique JTI per token | TokenService.cs:38 |
Recommended Additions
For even stronger security, consider adding:- Rate limiting - Throttle requests per IP (use middleware like AspNetCoreRateLimit)
- CAPTCHA - After 3 failed attempts, require CAPTCHA
- 2FA/MFA - Add TOTP support for high-value accounts
- Device fingerprinting - Detect token use from new devices
- Geolocation - Alert users to logins from unusual locations
- Password strength meter - Enforce stronger passwords (zxcvbn)
- Breach detection - Check passwords against HaveIBeenPwned
- Security questions - For account recovery
- Email verification - Verify email ownership on registration
- Audit log - Comprehensive activity log per user
Compliance Considerations
GDPR
Right to erasure: Set
IsActive = false and delete tokensData portability: Export user data via /api/auth/meBreach notification: Use logs to detect and report breaches within 72 hoursPCI DSS
Requirement 8: Strong authentication (PBKDF2 600k iterations)Requirement 10: Comprehensive audit loggingRequirement 6: Secure development (input validation, error handling)
NIST 800-63B
Level AAL2: Password + token-based authPassword storage: PBKDF2 with 600k iterations (compliant)Token lifetimes: 15min access, 7-day refresh (compliant)
OWASP Top 10
A01 Broken Access Control: JWT validation enforcedA02 Cryptographic Failures: Strong hashing, secure RNGA07 Auth Failures: Lockout, rotation, generic errors
Related Topics
Authentication Flow
See how these features integrate into the complete flow
Token Rotation
Deep dive into refresh token security
API Reference
Complete endpoint documentation