Search documentation of phoenix_kit

# PhoenixKit.Users.RateLimiter (phoenix_kit v1.6.19)

View Source

Rate limiting for authentication endpoints to prevent brute-force attacks.

This module provides comprehensive rate limiting protection for:

- Login attempts (prevents password brute-forcing)
- Magic link generation (prevents token enumeration)
- Password reset requests (prevents mass reset attacks)
- User registration (prevents spam account creation)

## Configuration

Rate limits can be configured in your application config:

    # config/config.exs
    config :phoenix_kit, PhoenixKit.Users.RateLimiter,
      login_limit: 5,                    # Max login attempts per window
      login_window_ms: 60_000,           # 1 minute window
      magic_link_limit: 3,               # Max magic link requests per window
      magic_link_window_ms: 300_000,     # 5 minute window
      password_reset_limit: 3,           # Max password reset requests per window
      password_reset_window_ms: 300_000, # 5 minute window
      registration_limit: 3,             # Max registration attempts per window
      registration_window_ms: 3600_000,  # 1 hour window
      registration_ip_limit: 10,         # Max registrations per IP per window
      registration_ip_window_ms: 3600_000 # 1 hour window

## Security Features

- Email-based rate limiting: Prevents targeted attacks on specific accounts
- IP-based rate limiting: Prevents distributed attacks from single sources
- Timing attack mitigation: Consistent response times for valid/invalid emails
- Exponential backoff: Automatically enforced through time windows
- Comprehensive logging: All rate limit violations are logged for security monitoring

## Usage Examples

    # Check login rate limit
    case PhoenixKit.Users.RateLimiter.check_login_rate_limit(email, ip_address) do
      :ok -> proceed_with_login()
      {:error, :rate_limit_exceeded} -> show_rate_limit_error()
    end

    # Check magic link rate limit
    case PhoenixKit.Users.RateLimiter.check_magic_link_rate_limit(email) do
      :ok -> generate_magic_link()
      {:error, :rate_limit_exceeded} -> show_cooldown_message()
    end

## Production Recommendations

- Use Redis backend for distributed systems (hammer_backend_redis)
- Monitor rate limit violations for security threats
- Adjust limits based on your application's usage patterns
- Consider implementing CAPTCHA after multiple violations

# Summary

## Functions

check_login_rate_limit(email, ip_address \\ nil)

Checks if login attempts are within rate limit.

check_magic_link_rate_limit(email)

Checks if magic link generation is within rate limit.

check_password_reset_rate_limit(email)

Checks if password reset requests are within rate limit.

check_registration_rate_limit(email, ip_address \\ nil)

Checks if registration attempts are within rate limit.

get_config()
get_remaining_attempts(action, identifier)

Gets the remaining attempts for a specific action and identifier.

reset_rate_limit(action, identifier) deprecated

Resets rate limit for a specific action and identifier.

# Functions

# check_login_rate_limit(email, ip_address \\ nil)

Checks if login attempts are within rate limit.

Returns `:ok` if the request is allowed, or `{:error, :rate_limit_exceeded}` if the limit is exceeded.

This function implements dual rate limiting:

- Per-email rate limiting (prevents targeted attacks on specific accounts)
- Per-IP rate limiting (prevents distributed brute-force attacks)

## Examples

    iex> PhoenixKit.Users.RateLimiter.check_login_rate_limit("user@example.com", "192.168.1.1")
    :ok

    # After 5 failed attempts:
    iex> PhoenixKit.Users.RateLimiter.check_login_rate_limit("user@example.com", "192.168.1.1")
    {:error, :rate_limit_exceeded}

# check_magic_link_rate_limit(email)

Checks if magic link generation is within rate limit.

Returns `:ok` if the request is allowed, or `{:error, :rate_limit_exceeded}` if the limit is exceeded.

Magic links have stricter rate limits to prevent token enumeration attacks.

## Examples

    iex> PhoenixKit.Users.RateLimiter.check_magic_link_rate_limit("user@example.com")
    :ok

    # After 3 requests in 5 minutes:
    iex> PhoenixKit.Users.RateLimiter.check_magic_link_rate_limit("user@example.com")
    {:error, :rate_limit_exceeded}

# check_password_reset_rate_limit(email)

Checks if password reset requests are within rate limit.

Returns `:ok` if the request is allowed, or `{:error, :rate_limit_exceeded}` if the limit is exceeded.

Password reset requests have moderate rate limits to prevent mass reset attacks while still allowing legitimate users to recover their accounts.

## Examples

    iex> PhoenixKit.Users.RateLimiter.check_password_reset_rate_limit("user@example.com")
    :ok

    # After 3 requests in 5 minutes:
    iex> PhoenixKit.Users.RateLimiter.check_password_reset_rate_limit("user@example.com")
    {:error, :rate_limit_exceeded}

# check_registration_rate_limit(email, ip_address \\ nil)

Checks if registration attempts are within rate limit.

Returns `:ok` if the request is allowed, or `{:error, :rate_limit_exceeded}` if the limit is exceeded.

Registration has dual rate limiting:

- Per-email rate limiting (prevents spam account creation with same email)
- Per-IP rate limiting (prevents mass account creation from single source)

## Examples

    iex> PhoenixKit.Users.RateLimiter.check_registration_rate_limit("user@example.com", "192.168.1.1")
    :ok

    # After limit exceeded:
    iex> PhoenixKit.Users.RateLimiter.check_registration_rate_limit("user@example.com", "192.168.1.1")
    {:error, :rate_limit_exceeded}

# get_config()

# get_remaining_attempts(action, identifier)

Gets the remaining attempts for a specific action and identifier.

Returns the number of attempts remaining before rate limit is exceeded.

For login and registration actions, returns the email-based limit. For magic_link and password_reset, returns the limit for the email.

Note: With Hammer 7.x, this uses the get/2 function to retrieve the current count.

## Examples

    iex> PhoenixKit.Users.RateLimiter.get_remaining_attempts(:login, "user@example.com")
    5

    iex> PhoenixKit.Users.RateLimiter.get_remaining_attempts(:magic_link, "user@example.com")
    3

# reset_rate_limit(action, identifier)

This function is deprecated. Hammer 7.x removed delete_buckets. Rate limits expire after their time window..

Resets rate limit for a specific action and identifier.

DEPRECATED: Hammer 7.x removed `delete_buckets` with no replacement. This function now returns an error as Backend.set/3 requires positive integers (cannot set to 0).

Rate limits will naturally expire after their configured window period.

## Migration

- For testing: Use `Application.put_env` to disable rate limiting
- For admin intervention: Wait for the time window to expire
- For immediate reset: Restart the application (clears ETS tables)

See: https://hexdocs.pm/hammer/upgrade-v7.html

## Examples

    iex> PhoenixKit.Users.RateLimiter.reset_rate_limit(:login, "email:user@example.com")
    {:error, :not_supported}