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​