Prompt
How do I set up an access control gateway for mTLS and JWT on internal APIs?
Latest observation
A good way to think about this is:
- mTLS proves the caller’s workload/service identity at the transport layer.
- JWT carries user/client/app authorization claims at the application layer.
- The gateway enforces both before requests reach internal APIs.
Recommended architecture
Place an API gateway / reverse proxy in front of your internal services that can:
- Terminate or pass through mTLS
- Validate client certificates
- Verify JWTs
- Map identity + claims to authorization policies
- Forward trusted identity context to backend services
Common options:
- Envoy
- NGINX
- Kong
- Traefik
- Service mesh ingress / east-west gateways like Istio or Linkerd (depending on your environment)
Request flow
Typical flow:
- Client connects to gateway over TLS with client certificate
- Gateway validates the client certificate against a trusted CA
- Client also sends an Authorization: Bearer <JWT>
- Gateway verifies:
- JWT signature
- issuer (
iss) - audience (
aud) - expiration (
exp) - scopes / roles / claims
- Gateway checks policy:
- Is this certificate identity allowed?
- Is this JWT subject/client allowed for this route?
- Do the scopes match the endpoint?
- Gateway forwards request to backend with:
- authenticated principal info
- selected claims
- optional upstream headers
Key design decisions
1. Decide how mTLS and JWT are combined
You generally have two patterns:
Pattern A: Both required
Best for high-trust internal APIs.
- mTLS authenticates the machine/service
- JWT authenticates the user/app context
- Gateway requires both to be valid
Use this when:
- internal APIs are sensitive
- you want defense in depth
- service-to-service calls also need end-user delegation
Pattern B: mTLS for service identity, JWT only on some routes
Useful when:
- some endpoints are service-to-service only
- some endpoints are user-facing and need JWT
- different routes have different policy requirements
2. Use a strong identity model
With mTLS, make sure certificates encode a stable identity:
- SPIFFE IDs are a strong option
- subject/OU/CN can work, but are less clean
Example identity:
spiffe://company.prod/service/payments-api
Then map that identity to allowed routes and permissions.
3. Validate JWTs at the gateway, not in every service
Usually the gateway should:
- verify the token cryptographically
- enforce coarse-grained authorization
Backend services can then:
- trust gateway headers only if network is isolated
- optionally re-check token/claims for defense in depth
Implementation checklist
A. Set up certificate authority and mTLS
You need:
- a root CA or internal PKI
- client certificates for callers
- server certificate for the gateway
Recommended practices:
- use short-lived certs
- automate issuance/rotation
- revoke or expire quickly instead of relying heavily on CRLs
For Kubernetes/service mesh environments:
- consider cert-manager
- consider SPIRE/SPIFFE
- or service mesh identity management
B. Configure the gateway to require client certs
Gateway should:
- present its own server cert
- require a valid client certificate
- trust only your internal CA
- reject unknown CAs
Also:
- verify SANs if possible
- avoid relying solely on CN
- require strong TLS versions and ciphers
C. Configure JWT verification
Gateway should validate:
- signature using JWKS or a trusted public key
issaudexp,nbf- optional
azp,scope,roles,tenant, etc.
Prefer:
- RS256 / ES256
- rotating keys via JWKS
- short-lived access tokens
Avoid:
- accepting
alg=none - overly broad audiences
- long-lived tokens for internal APIs
D. Define authorization policies
Common policy dimensions:
- route
- HTTP method
- mTLS identity
- JWT subject/client ID
- scopes/roles
- tenant
- environment
Example rules:
spiffe://company.prod/service/frontendcan callGET /orders/*- JWT
scope=orders.readrequired forGET /orders/* - JWT
scope=orders.writerequired forPOST /orders
E. Forward identity securely
After validation, gateway may forward:
X-Authenticated-Client-IdX-Authenticated-PrincipalX-Forwarded-UserX-Forwarded-Scopes
Important:
- strip any incoming spoofed identity headers from clients
- only the gateway should set trusted identity headers
- internal services should reject requests bypassing the gateway
Example policy model
For an endpoint:
POST /internal/payments/refund
Require:
- mTLS cert from
spiffe://company.prod/service/support-toolorspiffe://company.prod/service/orders-api - JWT with:
iss = https://auth.company.comaud = internal-paymentsscopecontainspayments.refundsubmatches approved operator or service account
Security best practices
- Enforce TLS 1.2+, ideally TLS 1.3
- Use short-lived certificates
- Use short-lived JWTs
- Validate all claims strictly
- Centralize policy management
- Use least privilege per route
- Log:
- cert identity
- JWT
sub - client ID
- route
- decision outcome
- Monitor:
- failed cert auth
- token validation errors
- unusual route access
- Rotate signing keys and CA roots safely
- Prevent direct access to backend services except from the gateway
Example with Envoy conceptually
Envoy can:
- require downstream client certs
- validate JWT using
jwt_authn - use RBAC filters for authorization
- forward selected headers to upstream services
High-level pieces:
DownstreamTlsContextfor mTLSjwt_authnfilter for JWT verificationrbacfilter for allow/deny rules
Common pitfalls
- Trusting JWT without checking mTLS identity
- Allowing services to bypass the gateway
- Not validating
aud - Using weak or manual certificate handling
- Accepting user-supplied identity headers
- Not separating service identity from user identity
- Long-lived tokens/certs
- No revocation/rotation strategy
A practical recommendation
If you want a robust setup quickly:
- Use Envoy or Kong as gateway
- Use SPIFFE/SPIRE for mTLS identities
- Use your IdP’s JWKS for JWT verification
- Enforce policies centrally at the gateway
- Keep internal services private so only the gateway can reach them
If you want, I can also provide:
- a sample Envoy config for mTLS + JWT,
- a Kubernetes setup with Ingress/Gateway API,
- or a step-by-step architecture for your specific stack.
Observation history
See 2 earlier observations
Create a free Obsurfable account to unlock historical responses, model comparisons, and deeper brand intelligence.
How did Obsurfable measure this prompt?
Obsurfable records AI answers to buyer-style prompts in its research corpus (3 observations for this page). Metrics are distributions over observations, not a single static ranking.
Which AI systems does Obsurfable collect answers from?
OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, and Meta AI.