Skip to main content
FastAPI, Django, and Flask support middleware that runs before selected route handlers. TrustGuard middleware evaluates the incoming HTTP body at that point. The middleware sees only the incoming HTTP body. It does not see content added by the handler or model calls made outside the request.

Integration capabilities

Your middleware enforces the verdict. Return a response on block, and write transformed_payload back to the request body when present. Logging the verdict and calling call_next provides monitoring only.

Before you start

Create the policy in Observe mode. Observe records decisions in Activity without enforcing them. Review the results, then switch the policy to Enforce. See Policies.

1. Install

2. Guard the request path

Build the client once at module scope and reuse it. The middleware reads the body, requests a verdict, and handles it before calling the route handler:
Three parts of the example determine enforcement:
  • if response.is_blocked: return before call_next. Without it, the finding is recorded and the request reaches your handler anyway.
  • request._body = …: a DLP rule masks by rewriting the payload, and request._body is where Starlette caches the body it will hand the handler. Assign the transformed body so the route receives the masked version.
  • AsyncTrustGuard, not TrustGuard: in an async framework, the synchronous client blocks the event loop for the length of every evaluation, on every request.
On the request path, consumer_id and session_id usually come from an identity header and session cookie. consumer_id routes the request to a per-consumer policy and attributes the finding in Activity. session_id groups turns in a conversation. Where the middleware attaches differs by framework; the guard() call does not: Django and Flask serve synchronously in the common deployment, so the synchronous TrustGuard client is the right one there.

3. Scope it to the AI routes

Middleware runs on every request by default, including static assets and health checks. Filter by path or mount it only on the router that contains AI routes. The request.method == "POST" condition in the example is a starting point; add the path filters required by your application.

4. Evaluate the response too

The middleware above covers input. The completion your handler produces is a second, separate evaluation with direction="output", and the natural place for it is the route itself, using the Python SDK client you already built:
Set direction on every call. It selects the detector phase: input before the model and output after it. The field defaults to input, so omitting it from the second call prevents Output-phase rules from running. The response body field remains input on an output call; direction identifies the phase.
If the route streams the completion, tokens have already been delivered when the assembled text becomes available for evaluation. An output-side block cannot prevent delivery. Buffer the stream until a verdict is available if the route requires preventive output enforcement. Input enforcement is unaffected.

5. Verify

  1. Send a POST to a wrapped route with a jailbreak string in the body.
  2. Confirm the event in TrustGuard Activity, under the consumer_id the middleware sent.
  3. Reconcile the run with the console using trace_id from the response. It is the same identifier the finding carries in Activity.
In Observe mode, the request proceeds and the finding appears in Activity. In Enforce mode, the same request returns 403 with {"detail": "Blocked by TrustGuard"}.

Reference

Coverage

Use middleware to apply the same check to selected HTTP routes. Background jobs, queue consumers, and internal calls bypass it; instrument those call sites with the SDK. ⚠️ Your middleware enforces the verdict. The 403 branch and the request._body assignment turn a verdict into a block or redaction. LLM output requires the second evaluation in step 4. Tool calls are outside the middleware scope. The middleware has no hook that fires when an agent chooses a tool or reads a result. Guard the tool dispatch with the SDK using protocol="mcp", or route MCP through TrustGate. Limits. Use the async client in async frameworks, or every evaluation blocks the event loop. Scope the middleware to the AI routes so unrelated endpoints do not pay the latency. Output coverage needs a second evaluation on the response.

What is evaluated

The middleware sends the raw body as {"input": body.decode()}, so what is evaluated is the whole request payload, not a prompt field you selected out of it. payload also accepts a full OpenAI, Anthropic, or Gemini provider body if the handler receives one.

Configuration

A block verdict still returns HTTP 200 from TrustGuard. The 403 in the example is returned by your service. The full response carries status, findings, transformed_payload, trace_id and request_id; see Evaluate API for the contract behind the client. Decide what an unreachable TrustGuard does. Wrap the call and handle timeouts and connection errors explicitly. See the SDK’s fail-open/fail-closed guidance and set a timeout that does not hold requests open indefinitely. The five reduced statuses (block, ask, transform, report, allow) behave here as they do for any application collector; ask is advisory, because middleware has no one to prompt. See the SDK’s status table. Other languages and runtimes: Node.js middleware for Express and Next.js, or REST from any framework without an SDK.

Attributes

Middleware can send context available at the request layer: Both defaults in the snippet fall back to "". An empty consumer_id means no per-consumer policy routing and no attribution in Activity, so resolve the authenticated user before the middleware runs, or read the verified identity exposed by your authentication layer. Context produced by the handler, such as retrieved-document provenance, is not available to middleware that runs before the handler.

Troubleshooting