API Gateway Security Patterns


The API Gateway as Security Perimeter

An API gateway acts as the single entry point for all client-to-service communication in a microservices architecture. It is uniquely positioned to enforce security policies centrally, reducing complexity in individual services and providing a consistent security layer.

Core Security Functions

Authentication and Authorization

The gateway validates tokens before requests reach backend services, offloading this responsibility from individual services.




# Kong Gateway authentication configuration


services:


- name: user-service


url: http://user-svc.internal:8080


routes:


- name: user-routes


paths:


- /api/users


plugins:


- name: jwt


config:


key_claim_name: iss


secret_is_base64: false


claims_to_verify:


- exp


- nbf


run_on_preflight: true








// Custom auth middleware in Express Gateway


const jwt = require('jsonwebtoken');




async function gatewayAuth(req, res, next) {


const token = req.headers.authorization?.replace('Bearer ', '');




try {


const decoded = jwt.verify(token, PUBLIC_KEY, {


algorithms: ['RS256'],


issuer: 'https://auth.example.com'


});




// Inject validated claims into downstream request


req.headers['x-user-id'] = decoded.sub;


req.headers['x-user-roles'] = decoded.roles.join(',');


req.headers['x-authenticated'] = 'true';




// Strip the original token from downstream


delete req.headers.authorization;


next();


} catch (err) {


return res.status(401).json({ error: 'Invalid token' });


}


}





Rate Limiting and Throttling

The gateway enforces global and per-service rate limits:




plugins:


- name: rate-limiting


config:


second: null


minute: 1000


hour: 50000


policy: local


fault_tolerant: true


hide_client_headers: false


redis:


host: redis.internal


port: 6379





IP Allowlisting and Blocklisting




plugins:


- name: ip-restriction


config:


allow:


- 10.0.0.0/8


- 172.16.0.0/12


deny:


- 10.0.0.42 # Specific blocked IP





Request Validation

Schema Validation

Validate request bodies against OpenAPI schemas at the gateway:




plugins:


- name: request-validator


config:


body_schema:


type: object


required:


- email


- password


properties:


email:


type: string


format: email


maxLength: 255


password:


type: string


minLength: 8


maxLength: 128


parameter_schema:


- in: query


name: page


schema:


type: integer


minimum: 1





Request Size Limiting




# Nginx as API gateway


http {


client_body_buffer_size 128k;


client_max_body_size 10M;


client_body_timeout 30s;




server {


listen 443 ssl;


server_name api.example.com;




location /api/ {


# Limit request size per endpoint


location /api/upload {


client_max_body_size 100M;


}




location /api/query {


client_max_body_size 1K;


}


}


}


}





TLS Termination

Terminate TLS at the gateway to encrypt traffic between clients and the gateway, and optionally re-encrypt between gateway and services:




server {


listen 443 ssl http2;


server_name api.example.com;




ssl_certificate /etc/ssl/certs/api.example.com.pem;


ssl_certificate_key /etc/ssl/private/api.example.com.key;


ssl_protocols TLSv1.2 TLSv1.3;


ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;


ssl_prefer_server_ciphers on;


ssl_session_cache shared:SSL:10m;


ssl_session_timeout 10m;




# Backend communication (re-encrypt)


location /api/internal/ {


proxy_pass https://internal-services;


proxy_ssl_verify on;


proxy_ssl_trusted_certificate /etc/ssl/certs/ca.crt;


}


}





CORS Management

Centrally manage CORS policies:




plugins:


- name: cors


config:


origins:


- https://app.example.com


- https://admin.example.com


methods:


- GET


- POST


- PUT


- DELETE


- PATCH


headers:


- Authorization


- Content-Type


exposed_headers:


- X-RateLimit-Remaining


credentials: true


max_age: 3600





Threat Detection and WAF

ModSecurity with OWASP CRS




# Enable WAF on the gateway


location /api/ {


modsecurity on;


modsecurity_rules_file /etc/nginx/modsecurity/owasp-crs/crs-setup.conf;




# Custom rules


modsecurity_rules '


# Block SQL injection patterns


SecRule REQUEST_URI "@rx (?i:(?:union[\s]+select|select[\s]+from))" \


"id:1000,deny,status:403,msg:\'SQL Injection blocked\'"




# Block common XSS attempts


SecRule ARGS "@rx ]*>" \


"id:1001,deny,status:403,msg:\'XSS blocked\'"




# Rate limit login attempts


SecRule IP:LOGIN_ATTEMPT "@gt 5" \


"id:1002,deny,status:429,msg:\'Brute force blocked\'"


';


}





GraphQL Security at the Gateway

GraphQL APIs need specialized protections:




plugins:


- name: graphql-proxy-cache


- name: graphql-rate-limiting


config:


max_queries_per_minute: 100


max_depth: 5


max_complexity: 1000





Security Headers at the Gateway

Apply consistent security headers across all responses:




plugins:


- name: response-transformer


config:


add:


headers:


- "Strict-Transport-Security: max-age=63072000; includeSubDomains; preload"


- "X-Content-Type-Options: nosniff"


- "X-Frame-Options: DENY"


- "Content-Security-Policy: default-src 'self'"


- "Referrer-Policy: strict-origin-when-cross-origin"





Audit Logging

Log all API requests centrally for security analysis:




plugins:


- name: file-log


config:


path: /var/log/api-gateway/access.log


custom_fields_by_lua:


client_ip: "ngx.var.remote_addr"


method: "ngx.var.request_method"


path: "ngx.var.request_uri"


status: "ngx.var.status"


latency: "ngx.var.upstream_response_time"


user_id: "ngx.var.http_x_user_id"





Summary

The API gateway is the ideal location to centralize security controls: authentication, rate limiting, request validation, IP restrictions, TLS termination, CORS management, and WAF rules. By enforcing these policies at the gateway, individual services remain simpler and can focus on business logic while maintaining a consistent security posture across your entire API surface.