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
| Setting | Value |
|---|---|
| Max requests | 10 |
| Time window | 5 minutes |
| Limit by | IP address |
| Response | 429 Too Many Requests |
Why Rate Limiting?
Protection Against
| Attack Type | How Rate Limiting Helps |
|---|---|
| Brute Force | Limits login attempts |
| Credential Stuffing | Blocks automated attacks |
| DDoS | Reduces server load |
| Bot Abuse | Prevents automated registration |
| Resource Exhaustion | Protects 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
| Action | Counts Against Limit |
|---|---|
| Google sign-in click | Yes |
| One Tap popup interaction | Yes |
| Failed authentication | Yes |
| Successful login | Yes |
| Page load | No |
| Button render | No |
Who Gets Rate Limited
| Traffic Source | Limited? |
|---|---|
| Regular users | Rarely (normal use) |
| Bots/scripts | Frequently |
| Shared IPs (NAT) | Possible (use caution) |
| Corporate networks | Possible (use caution) |
| VPN users | Depends 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_IPdetection
Security Plugins
Works alongside:
- Wordfence rate limiting (different scope)
- iThemes Security lockouts
- Sucuri firewall
Troubleshooting
Legitimate Users Getting Blocked
Causes:
- Shared IP (corporate/school)
- VPN with many users
- Testing repeatedly
- Double-clicking buttons
Solutions:
- Increase limit for known IPs
- Add message explaining wait time
- Check for JavaScript double-submit
- Consider IP whitelist
Rate Limit Not Working
Causes:
- Object cache issue
- Transient not saving
- IP detection wrong
- Plugin conflict
Solutions:
- Check transient storage
- Verify wp_options table
- Test IP detection
- Disable other plugins
Too Aggressive Blocking
Causes:
- Limit too low
- Window too long
- Counting wrong events
Solutions:
- Adjust via filters
- Shorten window
- 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
- Security Overview - All security measures
- Role Security - Permission controls
- Troubleshooting - Common issues