Skip to main content

Rate Limiting

OneTap Login implements rate limiting to prevent abuse, brute force attacks, and protect your server resources. This guide explains how rate limiting works and how to configure it.

Overview

What is Rate Limiting?

Rate limiting restricts how many authentication requests a user/IP can make within a time window:

Request 1: ✅ Allowed
Request 2: ✅ Allowed
...
Request 10: ✅ Allowed
Request 11: ❌ Blocked (rate limited)

Default Configuration

SettingValue
Max requests10
Time window5 minutes
Limit byIP address
Response429 Too Many Requests

Why Rate Limiting?

Protection Against

Attack TypeHow Rate Limiting Helps
Brute ForceLimits login attempts
Credential StuffingBlocks automated attacks
DDoSReduces server load
Bot AbusePrevents automated registration
Resource ExhaustionProtects API calls

Google's Requirements

Google recommends rate limiting for OAuth:

  • Prevents abuse of your Client ID
  • Protects your API quota
  • Required for some Google services

How It Works

Request Flow

Incoming authentication request

Check rate limit for IP

Under limit → Process request
Increment counter
Return response

Over limit → Return 429 error
Log attempt
Wait for window reset

Counter Management

IP: 192.168.1.1
├── Window start: 10:00:00
├── Current count: 7
└── Window end: 10:05:00

New request at 10:02:30:
├── Count < 10 → Allowed
├── New count: 8
└── Continue processing

Window Reset

Time: 10:05:01 (window expired)
├── Reset count to 0
├── Start new window
└── Next 10 requests allowed

Implementation Details

Storage

Rate limit counters stored via:

  • WordPress transients (default)
  • Object cache (if available)
  • Database fallback
// Simplified storage logic
$key = 'onetap_rate_' . md5($ip);
$count = get_transient($key);

if ($count === false) {
// New window
set_transient($key, 1, 300); // 5 minutes
} else {
// Increment
set_transient($key, $count + 1, 300);
}

IP Detection

OneTap detects real IP address:

// IP detection priority
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'] // Cloudflare
?? $_SERVER['HTTP_X_FORWARDED_FOR'] // Proxy/Load balancer
?? $_SERVER['HTTP_X_REAL_IP'] // Nginx proxy
?? $_SERVER['REMOTE_ADDR']; // Direct connection

// Sanitize
$ip = filter_var($ip, FILTER_VALIDATE_IP);

Response When Limited

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 180

{
"code": "rate_limited",
"message": "Too many requests. Please wait 3 minutes.",
"retry_after": 180
}

User Experience

When Rate Limited

User sees:

┌────────────────────────────────────────┐
│ ⚠️ Too Many Attempts │
│ │
│ You've made too many sign-in │
│ attempts. Please wait a few │
│ minutes and try again. │
│ │
│ [Try Again Later] │
└────────────────────────────────────────┘

Error Message Customization

In Settings > OneTap Login > General > Error Messages:

Default: "Too many login attempts. Please try again in a few minutes."

You can customize this message.

Legitimate vs Malicious Traffic

What Triggers Rate Limit

ActionCounts Against Limit
Google sign-in clickYes
One Tap popup interactionYes
Failed authenticationYes
Successful loginYes
Page loadNo
Button renderNo

Who Gets Rate Limited

Traffic SourceLimited?
Regular usersRarely (normal use)
Bots/scriptsFrequently
Shared IPs (NAT)Possible (use caution)
Corporate networksPossible (use caution)
VPN usersDepends on VPN IP

Configuration

Current Settings (Default)

Rate limiting is enabled by default with recommended settings:

  • 10 requests per 5 minutes per IP
  • Cannot be disabled (security feature)

Adjusting Limits (Advanced)

For special cases, use filters:

// Increase limit for specific IPs
add_filter('onetap_rate_limit_max', function($max, $ip) {
// Higher limit for office IP
if ($ip === '203.0.113.50') {
return 50;
}
return $max;
}, 10, 2);

// Increase time window
add_filter('onetap_rate_limit_window', function($window) {
return 600; // 10 minutes
});

Bypass for Specific IPs

// Whitelist specific IPs (use with caution)
add_filter('onetap_rate_limit_bypass', function($bypass, $ip) {
$whitelist = [
'203.0.113.50', // Office
'198.51.100.1', // Trusted server
];

if (in_array($ip, $whitelist)) {
return true;
}

return $bypass;
}, 10, 2);

Monitoring & Logging

What Gets Logged

When rate limited:

[2024-01-15 10:23:45] OneTap Rate Limit: IP 192.168.1.100 blocked (11/10 requests)

View Rate Limit Status

// Check current count for IP
$key = 'onetap_rate_' . md5($ip);
$count = get_transient($key);
echo "Current count: " . ($count ?: 0);

Analytics (PRO)

Rate limit events tracked in analytics:

  • Number of rate-limited requests
  • IPs most frequently limited
  • Time patterns

Interaction with Other Systems

Caching Plugins

Rate limiting works with:

  • WP Super Cache
  • W3 Total Cache
  • LiteSpeed Cache
  • WP Rocket

Note: Ensure AJAX/REST endpoints aren't cached.

Cloudflare

If using Cloudflare:

  • Cloudflare rate limiting is separate
  • Both can work together
  • Configure HTTP_CF_CONNECTING_IP detection

Security Plugins

Works alongside:

  • Wordfence rate limiting (different scope)
  • iThemes Security lockouts
  • Sucuri firewall

Troubleshooting

Legitimate Users Getting Blocked

Causes:

  1. Shared IP (corporate/school)
  2. VPN with many users
  3. Testing repeatedly
  4. Double-clicking buttons

Solutions:

  1. Increase limit for known IPs
  2. Add message explaining wait time
  3. Check for JavaScript double-submit
  4. Consider IP whitelist

Rate Limit Not Working

Causes:

  1. Object cache issue
  2. Transient not saving
  3. IP detection wrong
  4. Plugin conflict

Solutions:

  1. Check transient storage
  2. Verify wp_options table
  3. Test IP detection
  4. Disable other plugins

Too Aggressive Blocking

Causes:

  1. Limit too low
  2. Window too long
  3. Counting wrong events

Solutions:

  1. Adjust via filters
  2. Shorten window
  3. Review what's counted

Best Practices

Do's

  • Keep rate limiting enabled
  • Monitor blocked requests
  • Whitelist known good IPs carefully
  • Inform users about limits
  • Test from multiple IPs

Don'ts

  • Disable entirely
  • Set limits too high
  • Ignore blocked requests
  • Whitelist broad ranges
  • Forget about shared IPs

Performance Considerations

Overhead

Rate limiting adds minimal overhead:

  • One transient read per request
  • One transient write per request
  • ~1ms additional latency

With Object Cache

Using Redis/Memcached:

  • Even faster lookups
  • Better for high traffic
  • Recommended for scale

Hooks Reference

Filter: Max Requests

add_filter('onetap_rate_limit_max', function($max, $ip) {
return $max; // Default: 10
}, 10, 2);

Filter: Time Window

add_filter('onetap_rate_limit_window', function($window) {
return $window; // Default: 300 (5 minutes)
});

Filter: Bypass Check

add_filter('onetap_rate_limit_bypass', function($bypass, $ip) {
return $bypass; // Default: false
}, 10, 2);

Action: Rate Limited

add_action('onetap_rate_limited', function($ip, $count) {
// Log, notify, or take action
error_log("Rate limited IP: {$ip} with {$count} attempts");
}, 10, 2);

Next Steps