skip to content
logo
Table of Contents

API Security Fundamentals

Exposing an API without security measures leads to vulnerabilities like unauthorized access, data leaks, and injection attacks. This guide covers:

  • Authentication & Authorization
  • Rate Limiting
  • Input Validation
  • Secure Headers & OWASP Best Practices

Authentication: JWT for Secure User Sessions

Use JSON Web Tokens (JWT) to authenticate users.

Issue JWT on Login

import jwt from "jsonwebtoken";
const secretKey = "your_secret_key";
function generateToken(userId: string) {
return jwt.sign({ userId }, secretKey, { expiresIn: "1h" });
}

Verify JWT in Middleware

import { Request, Response, NextFunction } from "express";
import jwt from "jsonwebtoken";
const secretKey = "your_secret_key";
export function authMiddleware(
req: Request,
res: Response,
next: NextFunction,
) {
const token = req.headers.authorization?.split(" ")[1];
if (!token) return res.status(401).json({ error: "Unauthorized" });
try {
const decoded = jwt.verify(token, secretKey);
req.user = decoded;
next();
} catch {
res.status(403).json({ error: "Invalid token" });
}
}

Rate Limiting to Prevent Abuse

Prevent API abuse by limiting request rates per user.

import rateLimit from "express-rate-limit";
const limiter = rateLimit({
windowMs: 15 _ 60 _ 1000, // 15 minutes
max: 100, // Limit 100 requests per window
});
app.use(limiter);

For distributed rate limiting, use Redis.

import { createClient } from "redis";
const redisClient = createClient();
await redisClient.connect();
const key = `rate_limit:${req.ip}`;
const requests = await redisClient.incr(key);
if (requests > 100) return res.status(429).json({ error: "Too many requests" });
await redisClient.expire(key, 900);

Input Validation to Prevent Injection Attacks

Validate user input using Zod.

import { z } from "zod";
const userSchema = z.object({
username: z.string().min(3).max(20),
email: z.string().email(),
password: z.string().min(8),
});
function validateUserInput(input: unknown) {
return userSchema.parse(input);
}

If input is invalid, Zod throws an error, preventing SQL Injection and XSS.


Secure HTTP Headers with Helmet

Use Helmet.js to add security headers.

import helmet from "helmet";
app.use(helmet());

Headers Added:

  • X-Frame-Options: DENY (Prevents Clickjacking)
  • X-XSS-Protection: 1; mode=block (Mitigates XSS)
  • Strict-Transport-Security (Forces HTTPS)

OWASP Security Best Practices

  1. Use HTTPS – Prevents MITM attacks.
  2. Salt & Hash Passwords – Use bcrypt.
  3. Avoid Exposing Stack Traces – Set NODE_ENV=production.
  4. Limit CORS – Restrict API access to trusted domains.
import cors from "cors";
app.use(cors({ origin: "https://yourdomain.com" }));

Conclusion

  • Use JWT for authentication.
  • Rate limit to prevent API abuse.
  • Validate inputs to prevent injections.
  • Apply secure HTTP headers.
  • Follow OWASP best practices.

Securing an API is an ongoing process—regularly audit and monitor security logs.