Skip to main content

The Problem

Brute force attacks attempt to guess passwords by trying many combinations. You need to limit failed login attempts per account while allowing successful logins to proceed normally.

Solution: Per-User Rate Limit with Reset

Use a per-user rate limit on failed logins with manual reset on successful authentication. This protects individual accounts from credential stuffing attacks.

Configuration

convex/rateLimits.ts
Why token bucket? Tokens accumulate slowly (10 per hour), preventing rapid-fire password attempts. Each failed login consumes a token.

Complete Authentication Flow

Backend Mutations

convex/auth.ts

Using throws for Cleaner Code

Alternatively, use throws: true to automatically handle rate limit errors:
convex/auth.ts

Client-Side Usage

src/LoginForm.tsx

Testing the Protection

convex/test.ts

Common Variations

Security Best Practice: Always use the same error message for both “user not found” and “invalid password” to prevent account enumeration attacks.
Remember to reset! Always call rateLimiter.reset() on successful login. Otherwise, users will eventually get locked out even with correct credentials.
Consider logging failed login attempts to a separate table for security monitoring and alerting on suspicious patterns.