MILTON.ServiceDefaults
MILTON.ServiceDefaults is the standard .NET Aspire boilerplate, aggressively enhanced to encapsulate all cross-cutting concerns for the MILTON distributed application. It is applied recursively into the Program.cs bootstrapping of every individual service.
Architectural Intent
The goal of MILTON.ServiceDefaults is to guarantee that every node in the MILTON ecosystem operates with the exact same observability, health, resilience, and internal security baseline. By centralizing this configuration, we prevent configuration drift across microservices and reduce boilerplate in the application hosts.
Core Capabilities
1. Aspire Wiring & Observability (Extensions.cs)
The core AddServiceDefaults extension orchestrates:
- OpenTelemetry & Tracing: Instruments ASP.NET Core, HTTP clients, and runtime metrics, exporting telemetry via OTLP. This ensures distributed traces flow seamlessly across the API, Notification Service, and Document Generators.
- Health & Liveness Checks: Maps standard
/healthand/aliveendpoints, allowing the Aspire AppHost (and eventually Kubernetes) to monitor service lifecycles. - Resilience: Configures HTTP client defaults with standard retries, circuit breakers, and aggressive timeouts (e.g., 10-minute timeouts suitable for long-running AI operations).
- Service Discovery: Enables zero-configuration routing using Aspire’s service discovery mechanism.
2. Internal Identity & Edge Security
MILTON uses the Backend-For-Frontend (BFF) pattern. The MILTON.ReverseProxy (YARP Gateway) is the only component exposed to the internet. It handles OAuth/OIDC termination with Keycloak and proxies requests to downstream services.
To securely pass the authenticated user’s identity to the internal network without requiring downstream services to re-validate tokens, MILTON.ServiceDefaults implements a trusted header contract.
Keycloak Claims Transformation
At the Gateway edge, KeycloakClaimsTransformation flattens Keycloak’s deeply nested JWT payload. It extracts realm_access and resource_access arrays, mapping them into flat ASP.NET Core Role and custom permission claims.
Internal Header Authentication
Once transformed, the gateway injects the identity into HTTP headers (X-Internal-User-Id, X-Internal-Tenant-Id, etc.) and attaches a cryptographic shared secret (X-Internal-Auth).
Downstream services (like the API) use the InternalHeaderAuthenticationHandler to read these headers and reconstruct the ClaimsPrincipal statelessly.
sequenceDiagram participant Client participant Gateway as YARP Gateway (BFF) participant Keycloak as Keycloak (OIDC) participant Downstream as MILTON.API Client->>Gateway: HTTP Request (Cookie / Bearer) Gateway->>Keycloak: Validate Token Gateway->>Gateway: KeycloakClaimsTransformation (Flatten Roles) Gateway->>Gateway: Strip inbound X-Internal-* headers Gateway->>Gateway: Inject X-Internal-* headers + Secret Gateway->>Downstream: Proxied Request Downstream->>Downstream: InternalHeaderAuthenticationHandler Note right of Downstream: Validates Secret, reconstructs ClaimsPrincipal Downstream-->>Gateway: 200 OK Gateway-->>Client: 200 OK
By embedding this logic in MILTON.ServiceDefaults, any new microservice added to the MILTON ecosystem automatically inherits secure, tenant-aware identity resolution.