Rate Limiting
Protect magic link and OTP endpoints from abuse using Redis, database-backed, or in-memory rate limiters.
Rate Limiting
The magic link and OTP plugins include built-in rate limiting to prevent email/SMS flooding and brute-force attacks on short passcodes.
How It Works
Every time sendVerificationToken or sendOTP is called, Himayah checks a rate limiter keyed on the user's email or identifier:
- Check: Has this identifier exceeded
rateLimitLimitrequests within the lastrateLimitWindowseconds? - If yes: Reject the request with
429 Too Many Requests - If no: Allow the request and increment the counter
The counter automatically resets after rateLimitWindow seconds.
Store Options
In-Memory (Default)
Out of the box, Himayah uses a process-local in-memory rate limiter.
Do not use in-memory rate limiting in production with multiple server instances or serverless deployments. Each process has its own isolated counter — a user can bypass limits by hitting different nodes. Use Redis or database rate limiting instead.
Redis Rate Limiting
Package: @himayah/rate-limit-redis
Stores counters in Redis with automatic TTL expiration. Works with ioredis, node-redis, and @upstash/redis.
Installation
Setup
RedisRateLimitStore automatically detects the Redis client type and uses the correct command signature. For clients that support PX (millisecond TTL precision), it uses SET key value PX ms. For others, it falls back to EXPIRE.
Key Prefix
The second argument to RedisRateLimitStore is an optional key prefix. Use this to namespace your rate limit keys if you share a Redis instance across multiple apps or environments:
Database Rate Limiting
If you don't want to manage a separate Redis instance, store rate limit counters directly in your main database. This is a great choice for lower-traffic apps or when you're already paying for a hosted database.
Schema
Add a rate_limits table to your schema:
Setup
DatabaseRateLimitStore is included in @himayah/core — no extra package needed. Expired entries are automatically treated as non-existent and cleaned up on the next write for the same key.
Configuring Limits Per Plugin
Rate limit parameters are configured per plugin, not globally:
The rateLimitStore you configure on createAuth is shared across all plugins that support rate limiting.
Comparison
| Feature | In-Memory | Database | Redis |
|---|---|---|---|
| Setup complexity | None | Minimal (one table) | Requires Redis server |
| Works with multiple instances | ❌ | ✅ | ✅ |
| Works on serverless/Edge | ❌ | ✅ | ✅ (Upstash) |
| Performance | Fastest | Moderate | Fast |
| Best for | Local development | Low-to-medium traffic | High-traffic / production |
