Api security
Skill Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack/plugins/devtools-pack/skills/api-security
A curated pack of custom Claude Code skills for developers — installable as a Claude Code plugin marketplace.
npx -y skills add Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack --skill api-securityAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
When to activate: API security, rate limiting, JWT auth, OAuth2, API keys, WAF, GraphQL security, BOLA, broken object level authorization
SKILL.md
6.3 KB, as published. Nobody here has run it
API Security Patterns
Authentication
# JWT verification — pin algorithm, check expiry
import jwt
from fastapi import HTTPException, Security
from fastapi.security import HTTPBearer
security = HTTPBearer()
def verify_token(token: str) -> dict:
try:
payload = jwt.decode(
token,
settings.JWT_PUBLIC_KEY,
algorithms=["RS256"], # Pin algorithm — never accept "none"
options={"require": ["exp", "iat", "sub"]},
audience="api.example.com",
)
return payload
except jwt.ExpiredSignatureError:
raise HTTPException(401, "Token expired")
except jwt.InvalidTokenError:
raise HTTPException(401, "Invalid token")
# API Key — hash stored, compared in constant time
import hashlib, hmac, secrets
def create_api_key() -> tuple[str, str]:
raw = secrets.token_urlsafe(32)
hashed = hashlib.sha256(raw.encode()).hexdigest()
return raw, hashed # return raw once, store hashed
def verify_api_key(provided: str, stored_hash: str) -> bool:
provided_hash = hashlib.sha256(provided.encode()).hexdigest()
return hmac.compare_digest(provided_hash, stored_hash)
Authorization — BOLA Prevention
# Broken Object Level Authorization — always check ownership
from fastapi import Depends
async def get_invoice(
invoice_id: int,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
invoice = await db.get(Invoice, invoice_id)
if not invoice:
raise HTTPException(404)
# CRITICAL: verify ownership — never skip this
if invoice.owner_id != current_user.id:
raise HTTPException(403, "Access denied") # Not 404 — don't leak existence
return invoice
# For admin endpoints — verify role server-side (not just in UI)
def require_role(role: str):
def dependency(user: User = Depends(get_current_user)):
if role not in user.roles:
raise HTTPException(403, f"Role {role} required")
return user
return dependency
Rate Limiting
# FastAPI with slowapi
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@app.post("/api/login")
@limiter.limit("5/minute") # 5 attempts per minute per IP
async def login(request: Request, credentials: LoginRequest):
...
@app.post("/api/send-otp")
@limiter.limit("3/hour") # Prevent OTP flooding
async def send_otp(request: Request):
...
# Nginx rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/m;
limit_req_zone $binary_remote_addr zone=auth:10m rate=5r/m;
location /api/ {
limit_req zone=api burst=20 nodelay;
limit_req_status 429;
}
location /api/auth/ {
limit_req zone=auth burst=3 nodelay;
limit_req_status 429;
}
Input Validation
from pydantic import BaseModel, validator, constr
import re
class CreateUserRequest(BaseModel):
username: constr(min_length=3, max_length=30, pattern=r'^[a-zA-Z0-9_]+$')
email: str
age: int
@validator('email')
def validate_email(cls, v):
if not re.match(r'^[^@]+@[^@]+\.[^@]+$', v):
raise ValueError('Invalid email format')
return v.lower().strip()
@validator('age')
def validate_age(cls, v):
if not 0 < v < 150:
raise ValueError('Invalid age')
return v
GraphQL Security
# Depth limiting — prevent deeply nested queries
from graphql import build_schema
from graphql_depth_limit import depth_limit_validator
schema = build_schema(type_defs)
# Reject queries deeper than 5 levels
validation_rules = [depth_limit_validator(max_depth=5)]
# Query complexity limiting
from graphql_query_complexity import QualityLimitRule
class ComplexityRule(QualityLimitRule):
def __init__(self, context):
super().__init__(context, max_complexity=100)
# Disable introspection in production
GRAPHQL_INTROSPECTION = settings.DEBUG # False in prod
# Field-level authorization
@strawberry.type
class User:
name: str
@strawberry.field
def email(self, info: Info) -> str:
if info.context.user.id != self.id and not info.context.user.is_admin:
raise PermissionError("Cannot view other users' email")
return self._email
Security Headers
# FastAPI middleware
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
class SecurityHeadersMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
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.pop("Server", None) # Don't expose server info
return response
app.add_middleware(SecurityHeadersMiddleware)
app.add_middleware(
CORSMiddleware,
allow_origins=["https://app.example.com"], # Explicit, never "*"
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["Authorization", "Content-Type"],
)
API Security Checklist
Authentication: JWT pins alg, API keys hashed, OAuth PKCE for SPAs
Authorization: BOLA checked server-side on every resource access
Rate Limiting: login ≤5/min, OTP ≤3/hr, general API ≤100/min
Input: schema validation on all inputs, content-type enforced
Output: no stack traces, no internal paths, minimal error details
Transport: HTTPS only, HSTS header, TLS 1.2+ minimum
Headers: security headers set, Server header removed
GraphQL: depth limit, complexity limit, introspection off in prod
Logging: log auth failures, 4xx/5xx, but NOT request bodies with PII