Loading
Add Redis rate limiting for forgot-password
Summary
- Add
RateLimiterServiceusing the existing Redis instance (hostredis, DB 9) with fixed-window counters - Enforce configurable per-email and per-IP limits on forgot-password before user lookup
- Keep the existing 5-minute per-user DB cooldown (
generated_at) - Keep clear UX messages for unknown / banned / suspended accounts
- Use a uniform denial message for rate-limit and cooldown denials: Too many requests. Please try again later.
- Add config + env knobs, unit/controller tests, and ignore
.phpunit.cache/
The previous 5-minute cooldown only applied to known accounts after a reset was issued. Requests with arbitrary email addresses could still generate unnecessary load on the email queue and SMTP pipeline. This adds request-layer protection without requiring new infrastructure.
Behavior
| Case | Result |
|---|---|
| Over email/IP Redis limit | Error: Too many requests… |
| Within 5 minutes of last reset (known user) | Error: Too many requests… |
| Unknown email | Error: Email address does not exist… |
| Banned / suspended | Existing banned / inactivity messages |
| Active user, allowed | Success + enqueue resetPassword |
Config (defaults)
| Knob | Default | Env |
|---|---|---|
| Email max / window | 5 / 3600s | RATE_LIMIT_FORGOT_EMAIL_MAX, RATE_LIMIT_FORGOT_EMAIL_WINDOW |
| IP max / window | 20 / 3600s | RATE_LIMIT_FORGOT_IP_MAX, RATE_LIMIT_FORGOT_IP_WINDOW |
| Fail open if Redis down | true |
RATE_LIMIT_FAIL_OPEN |
Files
src/Service/RateLimiterService.phpsrc/Controller/ForgotController.phpconfig/app.php,config/.env.example,.gitignore- Tests:
RateLimiterServiceTest,ForgotControllerTest, Redis fakes
Test plan
-
./vendor/bin/phpunit tests/TestCase/Service/RateLimiterServiceTest.php -
./vendor/bin/phpunit tests/TestCase/Controller/ForgotControllerTest.php(app container) - Manual: 6th submit for same email → Too many requests…
- Manual: unknown email (after clearing Redis limits) → Email address does not exist…
- Manual: real account, 2nd request within 5 minutes → Too many requests…
- Manual: successful reset still enqueues email job