Skip to content

ADR-005: ALB JWT Validation Over API Gateway

Status: Proposed Date: 2026-03-18 Deciders: AI Engineering NAMER

We need JWT-based authentication for the LLM gateway. The initial spec proposed API Gateway HTTP API ($260+/mo at 100 req/s) as the JWT validation layer because ALB’s native auth was cookie-based (browser only).

However, AWS launched ALB JWT Verification in November 2025 (GA in all regions). This is a new validate_token listener action that validates Bearer JWTs directly at the ALB — no cookies, no redirects, no API Gateway needed.

Use ALB native JWT validation (validate_token action) instead of API Gateway HTTP API for JWT authentication.

  1. Client sends Authorization: Bearer <jwt> to ALB
  2. ALB validates the JWT signature against the IdP’s JWKS endpoint
  3. ALB checks mandatory claims: iss (issuer) and exp (expiration)
  4. ALB also validates nbf (not before) and iat (issued at) if present
  5. If valid -> forward to target; if invalid -> return 401
  6. No cookies, no redirects, no browser interaction required

This is purpose-built for M2M and S2S communications.

ApproachMonthly Cost at 100 req/sMonthly Cost at 1000 req/s
ALB only (current)~$250~$250
ALB + API Gateway HTTP API~$510 (+$260)~$2,650 (+$2,400)
ALB with JWT validation~$250 (+$0)~$250 (+$0)

Savings: $260-$2,400/month — JWT validation is included in the ALB at no additional cost.

resource "aws_lb_listener" "https" {
load_balancer_arn = module.alb.arn
port = 443
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
certificate_arn = var.certificate_arn
default_action {
type = "validate_token"
validate_token {
token_type = "JWT"
issuer = "https://cognito-idp.${var.aws_region}.amazonaws.com/${aws_cognito_user_pool.main.id}"
jwks_endpoint = "https://cognito-idp.${var.aws_region}.amazonaws.com/${aws_cognito_user_pool.main.id}/.well-known/jwks.json"
on_token_valid {
type = "forward"
target_group_arn = module.alb.target_groups["gateway"].arn
}
on_token_invalid {
type = "deny"
}
}
}
}

ALB validates JWTs but does not issue them. Cognito is still needed as the identity provider:

  • Issue tokens via client_credentials (M2M) and authorization_code (user SSO)
  • Federate with Entra ID (SAML), Okta (OIDC)
  • Pre-Token Lambda to inject custom claims (org_unit, cost_center, team)
  • JWKS endpoint for ALB to verify signatures
CriteriaALB JWT ValidationAPI Gateway HTTP APIPortkey JWT Plugin
Cost$0 additional$260-2400/mo$0 additional
Latency~0ms (ALB-native)~10-15ms~1-2ms (in-process)
ManagedYes (AWS)Yes (AWS)No (OSS plugin)
Claims forwardingYes (in headers)Yes (in context)Yes (in hook context)
Per-route authYes (listener rules)Yes (route-level)No (global only)
WAF integrationYes (same ALB)Needs CloudFrontN/A

Positive: Zero additional cost, zero additional latency, zero additional infrastructure. JWT validation at the ALB is the simplest possible architecture. WAF stays on the same ALB.

Negative: Newer feature (Nov 2025) — less community experience than API Gateway. Cannot do per-client rate limiting at the auth layer (WAF rate rules by IP/header are still available). No usage plans or throttling (those would need application-layer implementation).