API Gateway in Go: validates (optionally) JWT, extracts the limit-key from the claim (default: sub)
2.4K
ipfwd/jwt-api-gateway-limiterGithub: https://github.com/ipfwd/jwt-api-gateway-limiter
API Gateway in Go: validates (optionally) JWT, extracts the key from the claim (default: sub), and applies rate-limit on routes (longest-prefix). Counters are stored in Redis.
Error format — JSON: {"error":{"code":429,"message":"Too many requests"}}.
Includes X-Request-Id (UUID v4), graceful shutdown, and HTTP server timeouts.
sub or any other, including nested user.id)jwt.public_key_pem_file is empty, the signature is not verifiedlimit = ceil(rps * period_seconds)X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-Reset (epoch seconds, exact window boundary)Retry-After (at 429)X-Request-Id (UUID v4)The repository already contains docker-compose.yml.
docker compose up --build
localhost:6379
Image: ipfwd/jwt-api-gateway-limiter
docker run --rm -p 8080:8080 \
-e CONFIG=/etc/gw/config.yaml \
-v $(pwd)/src/config.yaml:/etc/gw/config.yaml:ro \
-v $(pwd)/src/public.pem:/etc/gw/public.pem:ro \
ipfwd/jwt-api-gateway-limiter:latest
Gateway reads the configuration from the file, path is set by the CONFIG environment variable.
listen: ":8080"
redis:
addr: "redis:6379"
db: 0
password: ""
jwt:
public_key_pem_file: "" # if empty, the JWT signature is NOT verified
algorithms: ["RS256"] # valid alg
claim_key: "sub" # which claim to use as the key (can be "user.id")
issuer: "" # optional
audience: "" # optional
errors:
limit_reached: "Too many requests"
unavailable: "Service Unavailable"
not_found: "Route not found"
routes:
- id: "api"
prefix: "/api/"
upstream: "http://backend:80"
period: "100s"
rps: 10
- id: "api-admin"
prefix: "/api/admin/"
upstream: "http://backend:81"
period: "10s"
rps: 5
- id: "public"
prefix: "/"
upstream: "http://backend:82"
period: "10s"
rps: 1
The route is selected based on the longest prefix, for example, /api/admin/ takes precedence over /api/.
limit_per_window = ceil(rps * period_seconds)
All errors are returned in the following format:
{
"error": {
"code": 429,
"message": "Too many requests"
}
}
Examples:
curl -v -i http://localhost:8080/api/hello \
-H "Authorization: Bearer <JWT>"
X-RateLimit-Limit
X-RateLimit-Remaining
X-RateLimit-Reset
Retry-After (only) to 429)
X-Request-Id
If you need to enable validation, put the public key in PEM:
# private key
openssl genrsa -out private.pem 2048
# public key
openssl rsa -in private.pem -pubout -out public.pem
And specify in the config:
jwt:
public_key_pem_file: "/etc/gw/public.pem"
algorithms: ["RS256"]
cd src
go mod tidy
go build -o gateway ./main.go
./gateway
Project Structure
If jwt.public_key_pem_file is empty, the JWT signature is not verified. In this mode, anyone can forge a claim_key and bypass restrictions/obtain someone else's key.
It is recommended to enable JWT validation on the gateway or place a trusted component (ingress/auth proxy) in front of it to ensure JWT validity.
MIT
Content type
Image
Digest
sha256:9aa340fc7…
Size
6.5 MB
Last updated
3 days ago
docker pull ipfwd/jwt-api-gateway-limiter