install
source · Clone the upstream repo
git clone https://github.com/openclaw/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/brandonwise/api-security" ~/.claude/skills/clawdbot-skills-api-security && rm -rf "$T"
manifest:
skills/brandonwise/api-security/SKILL.mdsource content
API Security Best Practices
Implement secure API design patterns including authentication, authorization, input validation, rate limiting, and protection against common API vulnerabilities.
Description
USE WHEN:
- Designing new API endpoints
- Securing existing APIs
- Implementing authentication and authorization (JWT, OAuth 2.0, API keys)
- Setting up rate limiting and throttling
- Protecting against injection attacks (SQL, XSS, command)
- Conducting API security reviews or preparing for audits
- Handling sensitive data in APIs
- Building REST, GraphQL, or WebSocket APIs
DON'T USE WHEN:
- Need vulnerability scanning (use
skill)vulnerability-scanner - Building frontend-only apps with no API
- Need network-level security (firewalls, WAF config)
OUTPUTS:
- Secure authentication implementations (JWT, refresh tokens)
- Input validation schemas (Zod, Joi)
- Rate limiting configurations
- Security middleware examples
- OWASP API Top 10 compliance guidance
How It Works
Step 1: Authentication & Authorization
- Choose authentication method (JWT, OAuth 2.0, API keys)
- Implement token-based authentication
- Set up role-based access control (RBAC)
- Secure session management
- Implement multi-factor authentication (MFA)
Step 2: Input Validation & Sanitization
- Validate all input data
- Sanitize user inputs
- Use parameterized queries
- Implement request schema validation
- Prevent SQL injection, XSS, and command injection
Step 3: Rate Limiting & Throttling
- Implement rate limiting per user/IP
- Set up API throttling
- Configure request quotas
- Handle rate limit errors gracefully
- Monitor for suspicious activity
Step 4: Data Protection
- Encrypt data in transit (HTTPS/TLS)
- Encrypt sensitive data at rest
- Implement proper error handling (no data leaks)
- Sanitize error messages
- Use secure headers
JWT Authentication Implementation
Generate Secure JWT Tokens
// auth.js const jwt = require('jsonwebtoken'); const bcrypt = require('bcrypt'); app.post('/api/auth/login', async (req, res) => { try { const { email, password } = req.body; // Validate input if (!email || !password) { return res.status(400).json({ error: 'Email and password required' }); } // Find user const user = await db.user.findUnique({ where: { email } }); if (!user) { // Don't reveal if user exists return res.status(401).json({ error: 'Invalid credentials' }); } // Verify password const validPassword = await bcrypt.compare(password, user.passwordHash); if (!validPassword) { return res.status(401).json({ error: 'Invalid credentials' }); } // Generate JWT token const token = jwt.sign( { userId: user.id, email: user.email, role: user.role }, process.env.JWT_SECRET, { expiresIn: '1h', issuer: 'your-app', audience: 'your-app-users' } ); // Generate refresh token const refreshToken = jwt.sign( { userId: user.id }, process.env.JWT_REFRESH_SECRET, { expiresIn: '7d' } ); // Store refresh token in database await db.refreshToken.create({ data: { token: refreshToken, userId: user.id, expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) } }); res.json({ token, refreshToken, expiresIn: 3600 }); } catch (error) { console.error('Login error:', error); res.status(500).json({ error: 'An error occurred during login' }); } });
JWT Verification Middleware
// middleware/auth.js const jwt = require('jsonwebtoken'); function authenticateToken(req, res, next) { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN if (!token) { return res.status(401).json({ error: 'Access token required' }); } jwt.verify( token, process.env.JWT_SECRET, { issuer: 'your-app', audience: 'your-app-users' }, (err, user) => { if (err) { if (err.name === 'TokenExpiredError') { return res.status(401).json({ error: 'Token expired' }); } return res.status(403).json({ error: 'Invalid token' }); } req.user = user; next(); } ); } module.exports = { authenticateToken };
Input Validation (SQL Injection Prevention)
❌ Vulnerable Code
// NEVER DO THIS - SQL Injection vulnerability app.get('/api/users/:id', async (req, res) => { const userId = req.params.id; const query = `SELECT * FROM users WHERE id = '${userId}'`; const user = await db.query(query); res.json(user); }); // Attack: GET /api/users/1' OR '1'='1 → Returns all users!
✅ Safe: Parameterized Queries
app.get('/api/users/:id', async (req, res) => { const userId = req.params.id; // Validate input first if (!userId || !/^\d+$/.test(userId)) { return res.status(400).json({ error: 'Invalid user ID' }); } // Use parameterized query const user = await db.query( 'SELECT id, email, name FROM users WHERE id = $1', [userId] ); if (!user) { return res.status(404).json({ error: 'User not found' }); } res.json(user); });
✅ Safe: Using ORM (Prisma)
app.get('/api/users/:id', async (req, res) => { const userId = parseInt(req.params.id); if (isNaN(userId)) { return res.status(400).json({ error: 'Invalid user ID' }); } const user = await prisma.user.findUnique({ where: { id: userId }, select: { id: true, email: true, name: true } // Don't select sensitive fields }); if (!user) { return res.status(404).json({ error: 'User not found' }); } res.json(user); });
Schema Validation with Zod
const { z } = require('zod'); const createUserSchema = z.object({ email: z.string().email('Invalid email format'), password: z.string() .min(8, 'Password must be at least 8 characters') .regex(/[A-Z]/, 'Must contain uppercase letter') .regex(/[a-z]/, 'Must contain lowercase letter') .regex(/[0-9]/, 'Must contain number'), name: z.string().min(2).max(100), age: z.number().int().min(18).max(120).optional() }); function validateRequest(schema) { return (req, res, next) => { try { schema.parse(req.body); next(); } catch (error) { res.status(400).json({ error: 'Validation failed', details: error.errors }); } }; } app.post('/api/users', validateRequest(createUserSchema), async (req, res) => { // Input is validated at this point const { email, password, name, age } = req.body; const passwordHash = await bcrypt.hash(password, 10); const user = await prisma.user.create({ data: { email, passwordHash, name, age } }); const { passwordHash: _, ...userWithoutPassword } = user; res.status(201).json(userWithoutPassword); });
Rate Limiting
const rateLimit = require('express-rate-limit'); const RedisStore = require('rate-limit-redis'); const Redis = require('ioredis'); const redis = new Redis({ host: process.env.REDIS_HOST, port: process.env.REDIS_PORT }); // General API rate limit const apiLimiter = rateLimit({ store: new RedisStore({ client: redis, prefix: 'rl:api:' }), windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // 100 requests per window message: { error: 'Too many requests, please try again later', retryAfter: 900 }, standardHeaders: true, legacyHeaders: false, keyGenerator: (req) => req.user?.userId || req.ip }); // Strict rate limit for authentication const authLimiter = rateLimit({ store: new RedisStore({ client: redis, prefix: 'rl:auth:' }), windowMs: 15 * 60 * 1000, max: 5, // Only 5 login attempts per 15 minutes skipSuccessfulRequests: true, message: { error: 'Too many login attempts, please try again later', retryAfter: 900 } }); app.use('/api/', apiLimiter); app.use('/api/auth/login', authLimiter); app.use('/api/auth/register', authLimiter);
Security Headers (Helmet)
const helmet = require('helmet'); app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], scriptSrc: ["'self'"], imgSrc: ["'self'", 'data:', 'https:'] } }, frameguard: { action: 'deny' }, hidePoweredBy: true, noSniff: true, hsts: { maxAge: 31536000, includeSubDomains: true, preload: true } }));
Authorization Checks
❌ Bad: Only Authentication
app.delete('/api/posts/:id', authenticateToken, async (req, res) => { await prisma.post.delete({ where: { id: req.params.id } }); res.json({ success: true }); });
✅ Good: Authentication + Authorization
app.delete('/api/posts/:id', authenticateToken, async (req, res) => { const post = await prisma.post.findUnique({ where: { id: req.params.id } }); if (!post) { return res.status(404).json({ error: 'Post not found' }); } // Check if user owns the post or is admin if (post.userId !== req.user.userId && req.user.role !== 'admin') { return res.status(403).json({ error: 'Not authorized to delete this post' }); } await prisma.post.delete({ where: { id: req.params.id } }); res.json({ success: true }); });
Best Practices
✅ Do This
- Use HTTPS Everywhere - Never send sensitive data over HTTP
- Implement Authentication - Require authentication for protected endpoints
- Validate All Inputs - Never trust user input
- Use Parameterized Queries - Prevent SQL injection
- Implement Rate Limiting - Protect against brute force and DDoS
- Hash Passwords - Use bcrypt with salt rounds >= 10
- Use Short-Lived Tokens - JWT access tokens should expire quickly
- Implement CORS Properly - Only allow trusted origins
- Log Security Events - Monitor for suspicious activity
- Use Security Headers - Implement Helmet.js
- Sanitize Error Messages - Don't leak sensitive information
❌ Don't Do This
- Don't Store Passwords in Plain Text
- Don't Use Weak Secrets - Use strong, random JWT secrets
- Don't Trust User Input - Always validate and sanitize
- Don't Expose Stack Traces - Hide error details in production
- Don't Use String Concatenation for SQL
- Don't Store Sensitive Data in JWT - JWTs are not encrypted
- Don't Ignore Security Updates - Update dependencies regularly
- Don't Log Sensitive Data
OWASP API Security Top 10
- Broken Object Level Authorization - Always verify user can access resource
- Broken Authentication - Implement strong authentication mechanisms
- Broken Object Property Level Authorization - Validate which properties user can access
- Unrestricted Resource Consumption - Implement rate limiting and quotas
- Broken Function Level Authorization - Verify user role for each function
- Unrestricted Access to Sensitive Business Flows - Protect critical workflows
- Server Side Request Forgery (SSRF) - Validate and sanitize URLs
- Security Misconfiguration - Use security best practices and headers
- Improper Inventory Management - Document and secure all API endpoints
- Unsafe Consumption of APIs - Validate data from third-party APIs
Security Checklist
Authentication & Authorization
- Implement strong authentication (JWT, OAuth 2.0)
- Use HTTPS for all endpoints
- Hash passwords with bcrypt (salt rounds >= 10)
- Implement token expiration
- Add refresh token mechanism
- Verify user authorization for each request
- Implement role-based access control (RBAC)
Input Validation
- Validate all user inputs
- Use parameterized queries or ORM
- Sanitize HTML content
- Validate file uploads
- Implement request schema validation
- Use allowlists, not blocklists
Rate Limiting & DDoS Protection
- Implement rate limiting per user/IP
- Add stricter limits for auth endpoints
- Use Redis for distributed rate limiting
- Return proper rate limit headers
- Implement request throttling
Data Protection
- Use HTTPS/TLS for all traffic
- Encrypt sensitive data at rest
- Don't store sensitive data in JWT
- Sanitize error messages
- Implement proper CORS configuration
- Use security headers (Helmet.js)