Back to Articles
SecurityJun 20268 min read

Designing a Centralized Identity Gateway for 70+ Microservices

Auth architecture across heterogeneous actors: OIDC, mTLS, SAML, and OPA sidecars


#The Challenge of Decentralized Auth

In a rapidly growing service architecture, security starts to fray if auth logic is embedded inside individual applications. We faced a common distributed platform challenge: 70+ microservices written in different frameworks (Spring Boot, Micronaut, Node.js) with inconsistent token validation, SAML federations, and static API keys. This led to high maintenance overhead, auditing difficulties, and potential service-to-service vulnerability leaks.

Embedding authorization rules directly into microservice code creates a tight coupling that prevents centralized security governance and rapid policy updates.

#System Architecture Visualized

Centralized Identity Gateway Architecture Diagram

// Identity Gateway Topology: Ingress routing lanes leading to Envoy Proxies and Open Policy Agent (OPA) validation nodes.

#The Four-Lane Authentication Strategy

We designed a centralized identity gateway model that segregated traffic into four distinct lanes based on the calling actor type:

  • Lane 1: Internal Human Users (OIDC/OAuth2 authorization code flow with PKCE, managed via AWS Cognito).
  • Lane 2: External Enterprise Partners (SAML 2.0 federation mapping to fine-grained application roles).
  • Lane 3: Service-to-Service Communication (Mutual TLS (mTLS) with SPIFFE/SPIRE for cryptographically verifiable identity).
  • Lane 4: External Developers/System Integrators (HMAC signed requests and secure API tokens with rate-limiting policies).

Envoy and Open Policy Agent (OPA) Sidecar Model

To decouple authorization logic from application code, we introduced an Envoy proxy sidecar pattern. All ingress traffic to a microservice passes through Envoy, which delegates authorization requests to a local Open Policy Agent (OPA) sidecar process over gRPC. OPA evaluates access control based on policy rules written in Rego.

regoRead-Only
# Rego policy evaluating service-to-service access
package env.authz

default allow = false

# Allow access if client identity is explicitly authorized
allow {
    input.attributes.request.http.headers["x-spiffe-client-id"] == "spiffe://prod.local/ns/billing/sa/payment-processor"
    input.attributes.request.http.method == "POST"
    input.attributes.request.http.path == "/v1/charges"
}

# Allow human developers with administrative credentials
allow {
    claims := jwt_claims(input.attributes.request.http.headers["authorization"])
    "platform-admin" in claims.roles
}

#Eliminating Validation Latency: Introspection Caching

Querying an Identity Provider (IdP) for every microservice invocation would crush API performance. To solve this, we implemented JWT cryptographical verification using public keys (JWKS) cached in-memory at the gateway. For stateful API tokens, we utilized a low-latency Redis cache layer cluster with a write-through invalidation strategy, dropping validation overhead from ~80ms to less than 2ms.

Have questions about this pattern?

If you want to discuss authentication mechanisms, database scaling bottlenecks, or security automation in distributed platforms, let's schedule an engineering talk.

Get in Touch