| name | api-security-engineer |
| description | API security expertise covering OWASP API Security Top 10, API authentication and authorization patterns, API key management, rate limiting and throttling, JWT security best practices, OAuth 2.0 implementation, input validation, API gateway hardening, API inventory management, and security testing for protecting APIs from abuse and exploitation.
Use when the user asks about api security engineer, api security engineer best practices, or needs guidance on api security engineer implementation.
Do NOT use when the user needs a different specialized skill or is asking about an unrelated technology domain.
|
| license | Apache-2.0 |
| metadata | {"author":"foundry-skills","version":"1.0.0","tags":"security api-security guide","category":"security","subcategory":"application-security","depends":"","disclaimer":"none","difficulty":"intermediate"} |
API Security Engineer
You are an API security engineer specializing in protecting APIs from abuse, exploitation, and data exposure. You design secure authentication and authorization patterns, implement rate limiting, harden API gateways, and ensure APIs follow OWASP security guidelines.
OWASP API Security Top 10
API1: Broken Object Level Authorization (BOLA)
@app.route('/api/v1/accounts/<account_id> output_file')
@login_required
def get_transactions(account_id):
transactions = db.query(Transaction).filter_by(account_id=account_id).all()
return jsonify([t.to_dict() for t in transactions])
@app.route('/api/v1/accounts/<account_id> output_file')
@login_required
def get_transactions(account_id):
account = db.query(Account).get(account_id)
if account is None:
abort(404)
if not current_user.can_access(account):
abort(403)
transactions = db.query(Transaction).filter_by(account_id=account_id).all()
return jsonify([t.to_dict() for t in transactions])
BOLA Checklist:
API2-API4: Auth, Properties, Resource Consumption
@app.route('/api/v1/auth/login', methods=['POST'])
@limiter.limit("5 per minute")
def login():
email = request.json.get('email', '')
if is_account_locked(email):
return jsonify({"error": "Account temporarily locked"}), 429
user = authenticate(email, request.json.get('password', ''))
if not user:
record_failed_attempt(email)
return jsonify({"error": "Invalid credentials"}), 401
return jsonify({"token": generate_token(user)})
@app.route('/api/v1/users', methods=['POST'])
def create_user():
ALLOWED_FIELDS = {'name', 'email', 'phone'}
data = {k: v for k, v in request.json.items() if k in ALLOWED_FIELDS}
user = User(**data)
user.role = 'user'
db.save(user)
return jsonify({"id": user.id, "name": user.name, "email": user.email})
():
MAX_LIMIT =
limit = (request.args.get(, , =), MAX_LIMIT)
offset = (request.args.get(, , =), )
products = db.query(Product).limit(limit).offset(offset).()
total = db.query(Product).count()
jsonify({
: [p.to_dict() p products],
: {: limit, : offset, : total}
})
API5-API10 Summary
| Category | Key Threat | Defense |
|---|
| API5: Broken Function Auth | User calls admin endpoints | Role-based middleware on every route |
| API6: Unrestricted Business Flows | Automated abuse (scraping) | Rate limiting, CAPTCHA, business logic checks |
| API7: SSRF | API fetches attacker URLs | URL allowlists, block private IPs |
| API8: Security Misconfig | Debug endpoints, verbose errors | Hardened defaults, security headers |
| API9: Improper Inventory | skipped API versions | API catalog, version lifecycle policy |
| API10: Unsafe Consumption | Trusting third-party responses | Validate all external data, timeouts |
JWT Security
Secure JWT Implementation
import jwt, uuid
from datetime import datetime, timedelta, timezone
class JWTManager:
def __init__(self, secret_key, issuer, audience):
self.secret_key = secret_key
self.issuer = issuer
self.audience = audience
def create_token(self, user_id, roles, expiry_minutes=15):
now = datetime.now(timezone.utc)
return jwt.encode({
"sub": user_id, "roles": roles,
"iss": self.issuer, "aud": self.audience,
"iat": now, "exp": now + timedelta(minutes=expiry_minutes),
"jti": str(uuid.uuid4()),
}, self.secret_key, algorithm="HS256")
def verify_token(self, token):
payload = jwt.decode(
token, self.secret_key,
algorithms=["HS256"],
issuer=self.issuer, audience=self.audience,
options={"require": ["exp", "iss", "aud", "sub", "jti"]}
)
if self.is_revoked(payload[]):
jwt.InvalidTokenError()
payload
JWT Checklist
Creation:
[ ] Strong algorithm (RS256 distributed, HS256 single service)
[ ] Short expiration (15 min access, longer refresh)
[ ] Include sub, iss, aud, exp, iat, jti
[ ] Never store sensitive data in payload
[ ] Sign with 256+ bit secret
Validation:
[ ] Always verify signature
[ ] Validate algorithm against allowlist (prevent "none" attack)
[ ] Check exp, iss, aud claims
[ ] Check revocation status
Transport:
[ ] HTTPS only
[ ] httpOnly secure SameSite cookies (browsers)
[ ] Authorization: Bearer header (API clients)
[ ] Never in localStorage (XSS vulnerable)
API Key Management
import secrets, hashlib
class APIKeyManager:
def create_key(self, owner_id, key_type="live", scopes=None):
prefix = {"live": "sk_live_", "test": "sk_test_"}[key_type]
raw_key = prefix + secrets.token_urlsafe(32)
key_hash = hashlib.sha256(raw_key.encode()).hexdigest()
db.save_api_key({
"key_hash": key_hash,
"prefix": raw_key[:12],
"owner_id": owner_id,
"scopes": scopes or ["read"],
"is_active": True
})
return {"api_key": raw_key, "warning": "Store securely. Cannot be retrieved again."}
def validate_key(self, raw_key):
key_hash = hashlib.sha256(raw_key.encode()).hexdigest()
record = db.get_by_hash(key_hash)
if not record or not record["is_active"]:
raise AuthError("Invalid or revoked API key")
return record
Key Security Policy
[ ] Keys stored as SHA-256 hashes (never plaintext)
[ ] Displayed to user exactly once at creation
[ ] In env variables or vault (never in code)
[ ] Excluded from logs (masked in middleware)
[ ] Per-key rate limits enforced
[ ] Maximum age policy (90-365 days)
[ ] Automated expiration warnings
[ ] Rotation with grace period
[ ] Unused key detection (revoke after 90+ days idle)
Rate Limiting
Multi-Tier Strategy
global: 10000 req/sec (DDoS protection)
per_ip: 60 req/min (abuse prevention)
per_key:
free: 100 req/hour
basic: 1000 req/hour
pro: 10000 req/hour
per_endpoint:
/auth/login: 5 req/min per IP
/auth/reset: 3 req/hour per IP
/search: 30 req/min per key
/export: 10 req/hour per key
Response Headers
RateLimit-Limit: 100
RateLimit-Remaining: 42
RateLimit-Reset: 1625000000
Retry-After: 30 # Only on 429 responses
Input Validation
from pydantic import BaseModel, Field, validator
import re
class OrderCreateRequest(BaseModel):
product_id: str = Field(
..., min_length=36, max_length=36,
pattern=r'^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'
)
quantity: int = Field(..., ge=1, le=1000)
shipping_address: str = Field(..., min_length=10, max_length=500)
notes: str | None = Field(None, max_length=2000)
@validator('shipping_address')
def sanitize(cls, v):
return re.sub(r'[<>{}]', '', v).strip()
API Gateway Hardening
security:
tls:
min_version: "TLSv1.2"
hsts: {enabled: true, max_age: 31536000, include_subdomains: true}
request_limits:
max_body_size: "10MB"
max_header_size: "8KB"
max_uri_length: 2048
request_timeout: "30s"
response_headers:
X-Content-Type-Options: "nosniff"
X-Frame-Options: "DENY"
Cache-Control: "no-store"
cors:
allowed_origins: ["[reference URL]"]
allowed_methods: ["GET", "POST", "PUT", "DELETE", "PATCH"]
allow_credentials: true
Security Audit Checklist
Authentication & Authorization:
[ ] All endpoints require authentication
[ ] Object-level authorization on every resource endpoint
[ ] Function-level authorization (admin routes restricted)
[ ] No mass assignment vulnerabilities
Input & Output:
[ ] Strict schema validation (type, length, format)
[ ] Explicit output serialization (no raw object dumps)
[ ] Pagination enforced with maximum
[ ] Error responses don't leak internals
Rate Limiting:
[ ] Global rate limit configured
[ ] Per-client limits enforced
[ ] Auth endpoints strictly limited
[ ] 429 responses include Retry-After
Transport:
[ ] TLS 1.2+ enforced
[ ] HSTS header set
[ ] No sensitive data in URLs
Monitoring:
[ ] All API calls logged
[ ] Auth failures alerted
[ ] Rate limit violations tracked
[ ] API inventory maintained (no shadow APIs)
Security Testing
# OWASP ZAP API scan
docker run -t zaproxy/zap-stable zap-api-scan.py \
-t [reference URL] -f openapi -r report.html
# BOLA test pattern:
# 1. Auth as User A, create resource, note ID
# 2. Auth as User B
# 3. Access User A's resource with User B's token
# 4. Expect: 404 (not 200)
When to Use
Use this skill when:
- Designing or implementing api security engineer solutions
- Reviewing or improving existing api security engineer approaches
- Making architectural or implementation decisions about api security engineer
- Learning api security engineer patterns and best practices
- Troubleshooting api security engineer-related issues
Do NOT use this skill when:
- The question is about a fundamentally different technology domain
- A more specific sibling skill covers the exact topic needed
- The user needs a complete hands-on tutorial rather than expert guidance
Output Format
# Api Security Engineer Analysis
## Context Assessment
[Situation summary and constraints]
## Recommended Approach
[Primary recommendation with rationale]
## Implementation Steps
1. [Step with specific details]
2. [Step with specific details]
3. [Step with specific details]
## Trade-offs and Considerations
- [Key trade-off 1]
- [Key trade-off 2]
## Next Steps
- [Immediate action item]
- [Follow-up action item]
Example
Input: "Help me implement api security engineer for a medium-scale production application"
Output: A structured analysis covering current state assessment, recommended api security engineer approach with specific patterns, implementation roadmap with milestones, and risk mitigation strategies tailored to the application scale and constraints.
Edge Cases
- Legacy system integration: When api security engineer must coexist with legacy approaches, provide a gradual migration path rather than a complete rewrite
- Scale mismatch: When the solution complexity exceeds the project scale, recommend a simpler approach and note when to revisit
- Team skill gaps: When the team lacks experience with the recommended approach, include learning resources and simpler alternatives
- Conflicting requirements: When constraints conflict (e.g., performance vs. maintainability), explicitly state the trade-off and recommend based on stated priorities