HelloJohn / docs
Security

Rate Limiting

Protect your HelloJohn instance from brute force attacks, credential stuffing, and abuse with configurable rate limiting.

Rate Limiting

HelloJohn enforces rate limits on all authentication endpoints to prevent brute force attacks, credential stuffing, and abuse.

How rate limiting works

Rate limits are enforced per IP address using a sliding window algorithm. When Redis is configured, rate limit state is shared across all HelloJohn instances. Without Redis, each instance maintains its own in-memory state (not suitable for multi-instance deployments).

When a rate limit is exceeded, HelloJohn returns:

HTTP 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705329785

Default limits

EndpointLimitWindowScope
POST /v1/auth/sign-in10 attempts1 minutePer IP
POST /v1/auth/sign-up5 attempts1 hourPer IP
POST /v1/auth/magic-link5 requests10 minutesPer email + IP
POST /v1/auth/password-reset3 requests1 hourPer email
POST /v1/auth/token/refresh60 requests1 minutePer IP
POST /v1/auth/mfa/verify5 attempts5 minutesPer user session
GET /v1/auth/oauth/callback30 requests1 minutePer IP
Global API300 requests1 minutePer IP

Configuration

# Enable/disable rate limiting globally
RATE_LIMIT_ENABLED=true

# Login endpoint
RATE_LIMIT_LOGIN_MAX=10
RATE_LIMIT_LOGIN_WINDOW=1m

# Signup endpoint
RATE_LIMIT_SIGNUP_MAX=5
RATE_LIMIT_SIGNUP_WINDOW=1h

# Magic link
RATE_LIMIT_MAGIC_LINK_MAX=5
RATE_LIMIT_MAGIC_LINK_WINDOW=10m

# Global API rate limit
RATE_LIMIT_GLOBAL_MAX=300
RATE_LIMIT_GLOBAL_WINDOW=1m

Account lockout

In addition to IP-based rate limits, HelloJohn implements per-account lockout after repeated failures:

FailuresActionDuration
5 in 5 minSoft lock (CAPTCHA required)Until CAPTCHA solved
10 in 10 minHard lock (email required)Until email unlock link clicked
20 in 1 hourAccount disabledUntil admin re-enables

Configure lockout thresholds:

ACCOUNT_LOCKOUT_SOFT_THRESHOLD=5
ACCOUNT_LOCKOUT_SOFT_WINDOW=5m
ACCOUNT_LOCKOUT_HARD_THRESHOLD=10
ACCOUNT_LOCKOUT_HARD_WINDOW=10m
ACCOUNT_LOCKOUT_DISABLE_THRESHOLD=20
ACCOUNT_LOCKOUT_DISABLE_WINDOW=1h

IP allowlist and blocklist

Blocklist

Block specific IPs or CIDR ranges from all authentication endpoints:

POST /v1/security/ip-blocklist
Authorization: Bearer <admin_api_key>
Content-Type: application/json

{
  "ip": "203.0.113.42",
  "reason": "Credential stuffing attack",
  "expires_at": "2024-02-01T00:00:00Z"   // null = permanent
}

# Block a CIDR range
{
  "ip": "203.0.113.0/24",
  "reason": "Datacenter IP range"
}

Allowlist (bypass rate limits)

Allow trusted IPs (e.g., your test infrastructure) to bypass rate limits:

POST /v1/security/ip-allowlist
Authorization: Bearer <admin_api_key>
Content-Type: application/json

{
  "ip": "10.0.0.0/8",
  "reason": "Internal test network"
}

Environment variable blocklist

For self-hosted deployments, set blocked IPs at startup:

IP_BLOCKLIST=203.0.113.42,198.51.100.0/24
IP_ALLOWLIST=10.0.0.0/8,172.16.0.0/12

Trusted proxies

If HelloJohn is behind a reverse proxy, configure it to trust the X-Forwarded-For header for accurate IP-based rate limiting:

TRUST_PROXY=true
TRUST_PROXY_HOPS=1   # number of trusted proxy hops

Without this, all requests appear to come from the proxy's IP and rate limiting is ineffective.

Rate limiting in multi-instance deployments

When running multiple HelloJohn instances, a shared Redis instance is required for consistent rate limiting:

REDIS_URL=redis://redis:6379

Without Redis, each instance applies rate limits independently. A client could bypass per-IP limits by distributing requests across instances.

Monitoring rate limit events

Rate limit violations are recorded in the audit log as security.rate_limit_exceeded:

{
  "type": "security.rate_limit_exceeded",
  "actor": { "type": "anonymous" },
  "ip_address": "203.0.113.42",
  "metadata": {
    "endpoint": "/v1/auth/sign-in",
    "limit": 10,
    "window": "1m",
    "attempt_count": 11
  }
}

Set up an alert when security.rate_limit_exceeded events exceed a threshold — this is a leading indicator of a credential stuffing attack.

Custom rate limits per tenant

Enterprise tenants can have custom rate limits configured by an admin:

PATCH /v1/tenants/{tenant_id}/config
{
  "rate_limits": {
    "sign_in_max": 20,
    "sign_in_window": "1m",
    "sign_up_max": 10,
    "sign_up_window": "1h"
  }
}

For most production deployments:

RATE_LIMIT_ENABLED=true
RATE_LIMIT_LOGIN_MAX=10
RATE_LIMIT_LOGIN_WINDOW=1m
RATE_LIMIT_SIGNUP_MAX=5
RATE_LIMIT_SIGNUP_WINDOW=1h
RATE_LIMIT_MAGIC_LINK_MAX=5
RATE_LIMIT_MAGIC_LINK_WINDOW=10m
ACCOUNT_LOCKOUT_SOFT_THRESHOLD=5
ACCOUNT_LOCKOUT_HARD_THRESHOLD=10
TRUST_PROXY=true
REDIS_URL=redis://redis:6379

On this page