CLOUD
Security

API Security: Best Practices for Developers

CLOUD|April 14, 2026|3 min read|297 views
API Security: Best Practices for Developers

Authentication, rate limiting, input validation, CORS — 10 security practices for every API. With code examples.

API Security Best Practices

An unprotected API is an open door to your company's data. Every day, unprotected APIs face automated intrusion attempts. This guide covers the essential protection you must apply to any API.

Most Common API Security Issues

According to OWASP API Security Top 10 (2023):

  1. Broken Object Level Authorization — Most common: a user accessing another user's data
  2. Broken Authentication — Weak or broken authentication
  3. Excessive Data Exposure — Returning more data than the client needs
  4. Insufficient Rate Limiting — Allowing unlimited requests
  5. Mass Assignment — Accepting any field in the request without filtering

Authentication

Secure JWT

// Laravel - Secure JWT example
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

// Create Token
$payload = [
 'sub' => $user->id,
 'iat' => time,
 'exp' => time + 3600, // Expires in one hour
 'jti' => uniqid('', true), // Prevent replay attacks
];

$token = JWT::encode($payload, config('app.jwt_secret'), 'HS256');

// Verify Token
try {
 $decoded = JWT::decode($token, new Key(config('app.jwt_secret'), 'HS256'));
 $userId = $decoded->sub;
} catch (\Exception $e) {
 return response->json(['error' => 'Unauthorized'], 401);
}

API Keys for External Services

// Generate a secure API Key
$apiKey = bin2hex(random_bytes(32)); // 64 random characters

// Store as Hash (never store the original key)
$hashedKey = hash('sha256', $apiKey);

// In verification middleware
public function handle(Request $request, Closure $next)
{
 $apiKey = $request->header('X-API-Key');
 
 if (!$apiKey) {
 return response->json(['error' => 'API key required'], 401);
 }
 
 $hashedKey = hash('sha256', $apiKey);
 $key = ApiKey::where('key_hash', $hashedKey)
 ->where('is_active', true)
 ->first;
 
 if (!$key) {
 return response->json(['error' => 'Invalid API key'], 401);
 }
 
 return $next($request);
}

Authorization: Permission Verification

Broken Object Level Authorization

// Common mistake — allows any user to see any invoice
public function show($invoiceId)
{
 $invoice = Invoice::find($invoiceId); // Wrong!
 return response->json($invoice);
}

// Correct — verify resource ownership
public function show($invoiceId)
{
 $invoice = Invoice::where('id', $invoiceId)
 ->where('user_id', auth->id) // Correct
 ->firstOrFail;
 
 return response->json($invoice);
}

Rate Limiting

// Laravel — Custom Rate Limiting
RateLimiter::for('api', function (Request $request) {
 return [
 Limit::perMinute(60)->by($request->user?->id ?: $request->ip),
 Limit::perDay(10000)->by($request->user?->id ?: $request->ip),
 ];
});

Strict Rate Limiting for Sensitive Endpoints

// Strong protection for Login and Password Reset
RateLimiter::for('login', function (Request $request) {
 return Limit::perMinute(5)
 ->by($request->input('email') . '|' . $request->ip)
 ->response(function {
 return response->json([
 'error' => 'Too many attempts. Try again in 1 minute.'
 ], 429);
 });
});

Input Validation

// Strict validation of incoming data
public function store(Request $request)
{
 $validated = $request->validate([
 'name' => 'required|string|max:255',
 'email' => 'required|email:rfc,dns',
 'amount' => 'required|numeric|min:0|max:100000',
 'type' => 'required|in:invoice,receipt,quote',
 ]);
 
 // Use $validated only — never $request->all
 Invoice::create($validated);
}

Security Response Headers

// Middleware to add Security Headers
public function handle(Request $request, Closure $next)
{
 $response = $next($request);
 
 $response->headers->set('X-Content-Type-Options', 'nosniff');
 $response->headers->set('X-Frame-Options', 'DENY');
 $response->headers->set('X-XSS-Protection', '1; mode=block');
 $response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
 $response->headers->set('Content-Security-Policy', "default-src 'self'");
 
 // Hide server information
 $response->headers->remove('X-Powered-By');
 $response->headers->remove('Server');
 
 return $response;
}

Logging Security Events

// Log all failed authentication attempts
Event::listen(Failed::class, function ($event) {
 Log::warning('Failed login attempt', [
 'email' => $event->credentials['email'],
 'ip' => request->ip,
 'user_agent' => request->userAgent,
 'time' => now->toIso8601String,
 ]);
});

HTTPS Is Mandatory

Any API running on HTTP without TLS sends all data unencrypted. كلاود (cloud.net.sa) provides Let's Encrypt for free with automatic renewal — no excuse for an API without HTTPS.

# Redirect HTTP to HTTPS
server {
 listen 80;
 server_name api.yourcompany.com;
 return 301 https://$host$request_uri;
}

Conclusion

API security is not optional — it is a legal and ethical responsibility. Start with HTTPS + JWT + Rate Limiting + Input Validation, then add additional layers based on the sensitivity of your data.


Get Started

Need a secure environment? Choose a protected server with DDoS protection and advanced firewall. Review our SLA and Privacy Policy.

Share