How to Secure API Endpoints with Rate Limiting and Token Authentication
Building a secure API is the foundation of every modern application. Without adequate protection, your API endpoints are vulnerable to brute-force attacks, credential stuffing, and resource abuse. In this article, we will cover three essential security layers that every API must implement.
1. Rate Limiting - Restrict Request Volume
Rate limiting prevents a single client from sending too many requests in a short period. The simplest implementation uses a sliding window counter:
// PHP: Simple rate limiter (300 req/min per API key)
$window = date("Y-m-d H:i:00"); // round to minute
$stmt = $pdo->prepare("INSERT INTO api_rate_limit (key_id, window_start, count)
VALUES (?, ?, 1) ON DUPLICATE KEY UPDATE count = count + 1");
$stmt->execute([$key_id, $window]);
// Check if limit exceeded
$count = $pdo->query("SELECT count FROM api_rate_limit WHERE ...")->fetchColumn();
if ($count > 300) {
http_response_code(429);
header("Retry-After: 60");
exit(json_encode(["error" => "Rate limit exceeded"]));
}
This technique is used by many platforms including the OTPZap Public API which enforces a 300 requests/minute limit per API key with X-RateLimit-Remaining headers for transparency.
2. Bearer Token Authentication
Never send API keys as query parameters - use the Authorization: Bearer header. Store keys as hashes (SHA-256) in your database, never plaintext:
// Generate API key
$raw_key = "myapp_live_" . bin2hex(random_bytes(16));
$key_hash = hash("sha256", $raw_key);
// Store $key_hash in DB, show $raw_key to user ONCE only
// Validate request
$header = $_SERVER["HTTP_AUTHORIZATION"] ?? "";
preg_match("/Bearer (.+)/i", $header, $m);
$incoming_hash = hash("sha256", trim($m[1] ?? ""));
$key = $pdo->query("SELECT * FROM api_keys WHERE key_hash = ?")->fetch();
By storing hashes, even if your database is compromised, attackers cannot use the keys.
3. Webhook Signature Verification (HMAC)
If your API sends webhooks to client servers, always include a signature to prove payload authenticity:
// Sender (your server)
$body = json_encode($payload);
$sig = "sha256=" . hash_hmac("sha256", $body, $client_secret);
// Send header: X-Signature: $sig
// Receiver (client server)
$expected = "sha256=" . hash_hmac("sha256", $raw_body, $my_secret);
if (!hash_equals($expected, $_SERVER["HTTP_X_SIGNATURE"])) {
http_response_code(401);
exit("Invalid signature");
}
Use hash_equals() for constant-time comparison - this prevents timing attacks.
Conclusion
These three techniques - rate limiting, token auth, and HMAC signatures - form a solid defense-in-depth for any API. Implementation does not have to be complex; consistency across every endpoint is what matters.
If you are building an application that needs OTP verification via API, OTPZap provides a complete REST API with all the security best practices discussed in this article - including rate limiting, Bearer auth, and webhook signature verification.