
Api Security Hardening
- 780 installs
- 305 repo stars
- Updated March 4, 2026
- aj-geddes/useful-ai-prompts
api-security-hardening is a backend security skill that adds authentication, rate limiting, input validation, CORS, and security headers to REST APIs for developers hardening endpoints against common attacks.
About
api-security-hardening is a Claude Code skill from aj-geddes/useful-ai-prompts that implements comprehensive REST API protection including authentication, authorization, rate limiting, input validation, CORS, and attack-prevention middleware. It includes an overview, quick start, reference guides, and best-practices sections for new API development and security audit remediation. Developers reach for api-security-hardening when exposing endpoints publicly or closing gaps found during reviews. The workflow focuses on practical middleware patterns rather than theoretical checklists.
- Implements Helmet security headers, rate limiting, mongo sanitization, XSS cleaning, and HTTP parameter pollution protec
- Supports JWT authentication, input validation with validator.js, and CORS configuration
- Covers new API development, security audit remediation, production hardening, and compliance needs
- Protects against common attacks including injection, XSS, and abuse from public exposure
- Provides reference guides and best practices for high-traffic and public APIs
Api Security Hardening by the numbers
- 780 all-time installs (skills.sh)
- +9 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #435 of 2,203 Security skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill api-security-hardeningAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 780 |
|---|---|
| repo stars | ★ 305 |
| Security audit | 3 / 3 scanners passed |
| Last updated | March 4, 2026 |
| Repository | aj-geddes/useful-ai-prompts ↗ |
How do you harden REST APIs against common attacks?
Add authentication, rate limiting, input validation, CORS, and security headers to REST APIs.
Who is it for?
Backend developers shipping or remediating public REST APIs that need authentication, throttling, and input-validation controls.
Skip if: Frontend-only styling work or infrastructure provisioning where no API attack surface is being modified.
When should I use this skill?
The user is building new API endpoints, remediating a security audit, or asks for auth, rate limiting, CORS, or input validation on REST routes.
What you get
Secured REST endpoints with authentication, rate limiting, validation middleware, CORS policy, and security headers configured.
- Auth middleware configuration
- Rate-limit rules
- Validation and CORS policy
Files
API Security Hardening
Table of Contents
Overview
Implement comprehensive API security measures including authentication, authorization, rate limiting, input validation, and attack prevention to protect against common vulnerabilities.
When to Use
- New API development
- Security audit remediation
- Production API hardening
- Compliance requirements
- High-traffic API protection
- Public API exposure
Quick Start
Minimal working example:
// secure-api.js - Comprehensive API security
const express = require("express");
const helmet = require("helmet");
const rateLimit = require("express-rate-limit");
const mongoSanitize = require("express-mongo-sanitize");
const xss = require("xss-clean");
const hpp = require("hpp");
const cors = require("cors");
const jwt = require("jsonwebtoken");
const validator = require("validator");
class SecureAPIServer {
constructor() {
this.app = express();
this.setupSecurityMiddleware();
this.setupRoutes();
}
setupSecurityMiddleware() {
// 1. Helmet - Set security headers
this.app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
// ... (see reference guides for full implementation)Reference Guides
Detailed implementations in the references/ directory:
| Guide | Contents |
|---|---|
| Node.js/Express API Security | Node.js/Express API Security |
| Python FastAPI Security | Python FastAPI Security |
| API Gateway Security Configuration | API Gateway Security Configuration |
Best Practices
✅ DO
- Use HTTPS everywhere
- Implement rate limiting
- Validate all inputs
- Use security headers
- Log security events
- Implement CORS properly
- Use strong authentication
- Version your APIs
❌ DON'T
- Expose stack traces
- Return detailed errors
- Trust user input
- Use HTTP for APIs
- Skip input validation
- Ignore rate limiting
API Gateway Security Configuration
API Gateway Security Configuration
# nginx-api-gateway.conf
# Nginx API Gateway with security hardening
http {
# Security headers
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'" always;
# Rate limiting zones
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=auth_limit:10m rate=1r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
# Request body size limit
client_max_body_size 10M;
client_body_buffer_size 128k;
# Timeout settings
client_body_timeout 12;
client_header_timeout 12;
send_timeout 10;
server {
listen 443 ssl http2;
server_name api.example.com;
# SSL configuration
ssl_certificate /etc/ssl/certs/api.example.com.crt;
ssl_certificate_key /etc/ssl/private/api.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# API endpoints
location /api/ {
# Rate limiting
limit_req zone=api_limit burst=20 nodelay;
limit_conn conn_limit 10;
# CORS headers
add_header Access-Control-Allow-Origin "https://app.example.com" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
# Block common exploits
if ($request_method !~ ^(GET|POST|PUT|DELETE|HEAD)$ ) {
return 444;
}
# Proxy to backend
proxy_pass http://backend:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Auth endpoints with stricter limits
location /api/auth/ {
limit_req zone=auth_limit burst=5 nodelay;
proxy_pass http://backend:3000;
}
# Block access to sensitive files
location ~ /\. {
deny all;
return 404;
}
}
}Node.js/Express API Security
Node.js/Express API Security
// secure-api.js - Comprehensive API security
const express = require("express");
const helmet = require("helmet");
const rateLimit = require("express-rate-limit");
const mongoSanitize = require("express-mongo-sanitize");
const xss = require("xss-clean");
const hpp = require("hpp");
const cors = require("cors");
const jwt = require("jsonwebtoken");
const validator = require("validator");
class SecureAPIServer {
constructor() {
this.app = express();
this.setupSecurityMiddleware();
this.setupRoutes();
}
setupSecurityMiddleware() {
// 1. Helmet - Set security headers
this.app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true,
},
}),
);
// 2. CORS configuration
const corsOptions = {
origin: (origin, callback) => {
const whitelist = ["https://example.com", "https://app.example.com"];
if (!origin || whitelist.includes(origin)) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
credentials: true,
optionsSuccessStatus: 200,
methods: ["GET", "POST", "PUT", "DELETE"],
allowedHeaders: ["Content-Type", "Authorization"],
};
this.app.use(cors(corsOptions));
// 3. Rate limiting
const generalLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: "Too many requests from this IP",
standardHeaders: true,
legacyHeaders: false,
handler: (req, res) => {
res.status(429).json({
error: "rate_limit_exceeded",
message: "Too many requests, please try again later",
retryAfter: req.rateLimit.resetTime,
});
},
});
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // Stricter limit for auth endpoints
skipSuccessfulRequests: true,
});
this.app.use("/api/", generalLimiter);
this.app.use("/api/auth/", authLimiter);
// 4. Body parsing with size limits
this.app.use(express.json({ limit: "10kb" }));
this.app.use(express.urlencoded({ extended: true, limit: "10kb" }));
// 5. NoSQL injection prevention
this.app.use(mongoSanitize());
// 6. XSS protection
this.app.use(xss());
// 7. HTTP Parameter Pollution prevention
this.app.use(hpp());
// 8. Request ID for tracking
this.app.use((req, res, next) => {
req.id = require("crypto").randomUUID();
res.setHeader("X-Request-ID", req.id);
next();
});
// 9. Security logging
this.app.use(this.securityLogger());
}
securityLogger() {
return (req, res, next) => {
const startTime = Date.now();
res.on("finish", () => {
const duration = Date.now() - startTime;
const logEntry = {
timestamp: new Date().toISOString(),
requestId: req.id,
method: req.method,
path: req.path,
statusCode: res.statusCode,
duration,
ip: req.ip,
userAgent: req.get("user-agent"),
};
// Log suspicious activity
if (res.statusCode === 401 || res.statusCode === 403) {
console.warn("Security event:", logEntry);
}
if (res.statusCode >= 500) {
console.error("Server error:", logEntry);
}
});
next();
};
}
// JWT authentication middleware
authenticateJWT() {
return (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith("Bearer ")) {
return res.status(401).json({
error: "unauthorized",
message: "Missing or invalid authorization header",
});
}
const token = authHeader.substring(7);
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ["HS256"],
issuer: "api.example.com",
audience: "api.example.com",
});
req.user = decoded;
next();
} catch (error) {
if (error.name === "TokenExpiredError") {
return res.status(401).json({
error: "token_expired",
message: "Token has expired",
});
}
return res.status(401).json({
error: "invalid_token",
message: "Invalid token",
});
}
};
}
// Input validation middleware
validateInput(schema) {
return (req, res, next) => {
const errors = [];
// Validate request body
if (schema.body) {
for (const [field, rules] of Object.entries(schema.body)) {
const value = req.body[field];
if (rules.required && !value) {
errors.push(`${field} is required`);
continue;
}
if (value) {
// Type validation
if (rules.type === "email" && !validator.isEmail(value)) {
errors.push(`${field} must be a valid email`);
}
if (rules.type === "uuid" && !validator.isUUID(value)) {
errors.push(`${field} must be a valid UUID`);
}
if (rules.type === "url" && !validator.isURL(value)) {
errors.push(`${field} must be a valid URL`);
}
// Length validation
if (rules.minLength && value.length < rules.minLength) {
errors.push(
`${field} must be at least ${rules.minLength} characters`,
);
}
if (rules.maxLength && value.length > rules.maxLength) {
errors.push(
`${field} must be at most ${rules.maxLength} characters`,
);
}
// Pattern validation
if (rules.pattern && !rules.pattern.test(value)) {
errors.push(`${field} format is invalid`);
}
}
}
}
if (errors.length > 0) {
return res.status(400).json({
error: "validation_error",
message: "Input validation failed",
details: errors,
});
}
next();
};
}
// Authorization middleware
authorize(...roles) {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({
error: "unauthorized",
message: "Authentication required",
});
}
if (roles.length > 0 && !roles.includes(req.user.role)) {
return res.status(403).json({
error: "forbidden",
message: "Insufficient permissions",
});
}
next();
};
}
setupRoutes() {
// Public endpoint
this.app.get("/api/health", (req, res) => {
res.json({ status: "healthy" });
});
// Protected endpoint with validation
this.app.post(
"/api/users",
this.authenticateJWT(),
this.authorize("admin"),
this.validateInput({
body: {
email: { required: true, type: "email" },
name: { required: true, minLength: 2, maxLength: 100 },
password: { required: true, minLength: 8 },
},
}),
async (req, res) => {
try {
// Sanitized and validated input
const { email, name, password } = req.body;
// Process request
res.status(201).json({
message: "User created successfully",
userId: "123",
});
} catch (error) {
res.status(500).json({
error: "internal_error",
message: "An error occurred",
});
}
},
);
// Error handling middleware
this.app.use((err, req, res, next) => {
console.error("Unhandled error:", err);
res.status(500).json({
error: "internal_error",
message: "An unexpected error occurred",
requestId: req.id,
});
});
}
start(port = 3000) {
this.app.listen(port, () => {
console.log(`Secure API server running on port ${port}`);
});
}
}
// Usage
const server = new SecureAPIServer();
server.start(3000);Python FastAPI Security
Python FastAPI Security
# secure_api.py
from fastapi import FastAPI, HTTPException, Depends, Security, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from pydantic import BaseModel, EmailStr, validator, Field
import jwt
from datetime import datetime, timedelta
import re
from typing import Optional, List
import secrets
app = FastAPI()
security = HTTPBearer()
limiter = Limiter(key_func=get_remote_address)
# Rate limiting
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
# CORS configuration
app.add_middleware(
CORSMiddleware,
allow_origins=[
"https://example.com",
"https://app.example.com"
],
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["Content-Type", "Authorization"],
max_age=3600
)
# Trusted hosts
app.add_middleware(
TrustedHostMiddleware,
allowed_hosts=["example.com", "*.example.com"]
)
# Security headers middleware
@app.middleware("http")
async def add_security_headers(request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
response.headers["Content-Security-Policy"] = "default-src 'self'"
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
response.headers["Permissions-Policy"] = "geolocation=(), microphone=(), camera=()"
return response
# Input validation models
class CreateUserRequest(BaseModel):
email: EmailStr
name: str = Field(..., min_length=2, max_length=100)
password: str = Field(..., min_length=8)
@validator('password')
def validate_password(cls, v):
if not re.search(r'[A-Z]', v):
raise ValueError('Password must contain uppercase letter')
if not re.search(r'[a-z]', v):
raise ValueError('Password must contain lowercase letter')
if not re.search(r'\d', v):
raise ValueError('Password must contain digit')
if not re.search(r'[!@#$%^&*]', v):
raise ValueError('Password must contain special character')
return v
@validator('name')
def validate_name(cls, v):
# Prevent XSS in name field
if re.search(r'[<>]', v):
raise ValueError('Name contains invalid characters')
return v
class APIKeyRequest(BaseModel):
name: str = Field(..., max_length=100)
expires_in_days: int = Field(30, ge=1, le=365)
# JWT token verification
def verify_token(credentials: HTTPAuthorizationCredentials = Security(security)):
try:
token = credentials.credentials
payload = jwt.decode(
token,
"your-secret-key",
algorithms=["HS256"],
audience="api.example.com",
issuer="api.example.com"
)
return payload
except jwt.ExpiredSignatureError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token has expired"
)
except jwt.InvalidTokenError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token"
)
# Role-based authorization
def require_role(required_roles: List[str]):
def role_checker(token_payload: dict = Depends(verify_token)):
user_role = token_payload.get('role')
if user_role not in required_roles:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Insufficient permissions"
)
return token_payload
return role_checker
# API key authentication
def verify_api_key(api_key: str):
# Constant-time comparison to prevent timing attacks
if not secrets.compare_digest(api_key, "expected-api-key"):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid API key"
)
return True
# Endpoints
@app.get("/api/health")
@limiter.limit("100/minute")
async def health_check():
return {"status": "healthy"}
@app.post("/api/users")
@limiter.limit("10/minute")
async def create_user(
user: CreateUserRequest,
token_payload: dict = Depends(require_role(["admin"]))
):
"""Create new user (admin only)"""
# Hash password before storing
# hashed_password = bcrypt.hashpw(user.password.encode(), bcrypt.gensalt())
return {
"message": "User created successfully",
"user_id": "123"
}
@app.post("/api/keys")
@limiter.limit("5/hour")
async def create_api_key(
request: APIKeyRequest,
token_payload: dict = Depends(verify_token)
):
"""Generate API key"""
# Generate secure random API key
api_key = secrets.token_urlsafe(32)
expires_at = datetime.now() + timedelta(days=request.expires_in_days)
return {
"api_key": api_key,
"expires_at": expires_at.isoformat(),
"name": request.name
}
@app.get("/api/protected")
async def protected_endpoint(token_payload: dict = Depends(verify_token)):
return {
"message": "Access granted",
"user_id": token_payload.get("sub")
}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000, ssl_certfile="cert.pem", ssl_keyfile="key.pem")#!/bin/bash
# security-checklist.sh - Generate a security review checklist
# Usage: ./security-checklist.sh [--output checklist.md]
set -euo pipefail
OUTPUT="${{1:-/dev/stdout}}"
cat > "$OUTPUT" << 'CHECKLIST'
# Security Review Checklist
## Authentication & Authorization
- [ ] All endpoints require authentication
- [ ] Role-based access control implemented
- [ ] Session management is secure
## Input Validation
- [ ] All user inputs are validated
- [ ] SQL injection prevention
- [ ] XSS prevention
## Data Protection
- [ ] Sensitive data encrypted at rest
- [ ] Sensitive data encrypted in transit
- [ ] PII handling compliant
## TODO: Add domain-specific security checks
CHECKLIST
echo "Checklist generated: $OUTPUT" >&2
Related skills
How it compares
Use api-security-hardening for endpoint-level REST controls; pair with infrastructure or secrets skills for TLS, WAF, or vault configuration.
FAQ
What controls does api-security-hardening cover?
api-security-hardening covers authentication, authorization, rate limiting, input validation, CORS configuration, and security middleware to protect REST APIs against common vulnerabilities.
When should api-security-hardening be used?
Use api-security-hardening during new API development or security audit remediation when endpoints need practical auth, throttling, validation, and header hardening before production.
Is Api Security Hardening safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.