From cb7b1b86f5021f91a46bdd5b51095d7f1f46d446 Mon Sep 17 00:00:00 2001 From: Sharang Parnerkar <30073382+mighty840@users.noreply.github.com> Date: Wed, 20 May 2026 17:20:37 +0200 Subject: [PATCH] fix(m7.1): correct middleware layer order so JwksState is visible Axum applies layers outermost-first. With the previous ordering (`Extension(jwks_state)` first, `require_jwt_auth` last), the JWT middleware ran before the Extension layer attached `JwksState` to the request, so `request.extensions().get::()` always returned None and the middleware silently passed through every request as if Keycloak weren't configured. Verified end-to-end against the local CERTifAI Keycloak realm: - no token / bad token -> 401 - active / trial -> 200 read, write reaches handler - frozen -> 200 read, 402 on writes - archived -> 410 on every method The bug was invisible to the unit + integration tests because they construct the layer stack manually; only the live wiring exhibited it. Co-Authored-By: Claude Opus 4.7 (1M context) --- compliance-agent/src/api/server.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compliance-agent/src/api/server.rs b/compliance-agent/src/api/server.rs index 9b89714..99d9248 100644 --- a/compliance-agent/src/api/server.rs +++ b/compliance-agent/src/api/server.rs @@ -8,7 +8,7 @@ use tower_http::set_header::SetResponseHeaderLayer; use tower_http::trace::TraceLayer; use crate::agent::ComplianceAgent; -use crate::api::auth_middleware::{require_jwt_auth, JwksState}; +use crate::api::auth_middleware::{require_jwt_auth, require_tenant_status, JwksState}; use crate::api::routes; use crate::error::AgentError; @@ -44,9 +44,14 @@ pub async fn start_api_server(agent: ComplianceAgent, port: u16) -> Result<(), A jwks_url, }; tracing::info!("Keycloak JWT auth enabled for realm '{kc_realm}'"); + // Layers execute outermost-first. The Extension must run before + // require_jwt_auth so that middleware can read JwksState from + // request extensions, and the status gate must run after the + // JWT auth so TenantContext is in extensions. app = app - .layer(Extension(jwks_state)) - .layer(middleware::from_fn(require_jwt_auth)); + .layer(middleware::from_fn(require_tenant_status)) + .layer(middleware::from_fn(require_jwt_auth)) + .layer(Extension(jwks_state)); } else { tracing::warn!("Keycloak not configured - API endpoints are unprotected"); }