Rate Limits
Overview
Section titled “Overview”The auth service enforces rate limits on all sensitive endpoints using KV-backed sliding window counters. Rate limits fail closed — if KV is unavailable, the request is denied.
Limits
Section titled “Limits”| Endpoint | Limit | Window | Key |
|---|---|---|---|
| Password login | 5 attempts | 15 min | IP + project |
| PIN login | 5 attempts | 15 min | IP + project |
| Signup | 3 attempts | 1 hour | IP |
| Magic link send | 3 sends | 1 hour | |
| Token exchange | 20 requests | 60 sec | client_id |
| OIDC token | 20 requests | 60 sec | client_id |
Behavior
Section titled “Behavior”Fail Closed
Section titled “Fail Closed”Unlike many rate limiters that fail open (allow on error), the auth service denies requests when KV is unavailable. This prevents brute-force attacks during infrastructure issues.
Per-Project Isolation
Section titled “Per-Project Isolation”Login rate limits are scoped to IP + project. Being rate-limited on proj_gym doesn’t affect authentication attempts on proj_bot.
No Bypass
Section titled “No Bypass”There is no API key or header to bypass rate limits. Admin endpoints are also rate-limited (via the token exchange limit on proj_admin).
Resetting Rate Limits
Section titled “Resetting Rate Limits”Admins can reset rate limit counters for a project via the admin API:
curl -X POST https://auth.beshoy.ai/admin/projects/proj_gym/rate-limits/reset \ -H "Authorization: Bearer $ADMIN_TOKEN"This clears all KV counters for the project — useful after a legitimate user gets locked out.
Client Recommendations
Section titled “Client Recommendations”async function fetchWithRetry(url: string, options: RequestInit, maxRetries = 3) { let delay = 1000; for (let i = 0; i <= maxRetries; i++) { const res = await fetch(url, options); if (res.status !== 429) return res; if (i < maxRetries) { await new Promise((r) => setTimeout(r, delay)); delay = Math.min(delay * 2, 60000); } } throw new Error('Rate limited after retries');}