Azure API Management Integration
This guide walks through inserting HiddenLayer AI Runtime Security into an Azure API Management (APIM) pipeline to scan and act on both user inputs and model outputs (including blocking unsafe content and redacting PII) before they reach the LLM or are returned to the user.
Prerequisites
Azure
- An Azure APIM instance
- An API configured as a passthrough to an Azure OpenAI resource using the
/responsesendpoint and/or/chat/completions
HiddenLayer
- Access to a HiddenLayer SaaS or containerized (hybrid) instance
- A ruleset configured with the following policies:
- Prompt Injection: Block
- Code: Block (output at minimum; input optional)
- PII: Redact
- A project with that ruleset attached
This guide demonstrates redaction for custom PII entities, which can only be added to a ruleset via API. If you haven’t done that yet, standard entity redaction (e.g., <PHONE_NUMBER>) will still work. See Runtime Security Policy to learn how to configure custom entities.
Background: How APIM Policy Works
Azure APIM policy is written in a combination of XML and C#. Full documentation on policy options is available in the Microsoft APIM policy reference.
To edit policy from the Azure portal, navigate to the operation you want to moderate, then click the angle-bracket icon (</>) in either the Inbound Processing or Outbound Processing pane.
Policy is organized into four sections:
<inbound>: Runs before the request is forwarded to the backend (LLM). Use this to scan user inputs.<backend>: Controls how requests are forwarded.<outbound>: Runs after the backend responds. Use this to scan model outputs.<on-error>: Handles exceptions.
Complete Policy
The policy example below obtains a SaaS auth token, scans input with HiddenLayer in <inbound> (including optional block/redact), forwards the request to Azure OpenAI, then scans the model output in <outbound>. It supports both /chat/completions-style bodies (with system-role messages filtered out before scanning) and /responses-style bodies.
The full policy can be copied into your APIM instance and assumes SaaS detection (https://api.hiddenlayer.ai). Replace placeholder named values ({{hiddenlayer-client-id}}, {{hiddenlayer-client-secret}}, {{hiddenlayer-project-id}}, {{aoai-api-key}}) before deploying. You can define these as named variables in Azure API Management and reference them with {{ }} as shown.
The sections that follow explain each piece in detail.
How It Works: Section by Section
Calling HiddenLayer Inbound (User Input)
The inbound section intercepts the user’s request before it reaches the LLM and POSTs to HiddenLayer’s /detection/v1/interactions endpoint.
For /chat/completions requests, the policy builds a filtered copy of messages that omits system role entries (so the system prompt is never sent to HiddenLayer). It scans the latest user message content. For /responses-style bodies, it reads the input field (string or message array) instead.
Requests to HiddenLayer include Authorization (Bearer token from SaaS OAuth), HL-Project-Id, X-Correlation-ID (APIM RequestId), and X-Requester-Id (first hop from X-Forwarded-For, else client IP).
Responding Based on the HiddenLayer Evaluation
The policy reads evaluation.action from the JSON response (Block, Redact, or allow).
If HiddenLayer returns a non-2xx status or times out, the policy fails open: it traces the failure and forwards the original request to Azure OpenAI.
If the evaluation action is Block, the caller receives 403 with a JSON error body that includes correlation and event metadata.
If the evaluation action is Redact, the inbound body is rewritten using modified_data.input.messages[0].content (for chat completions, the last user message is updated; for /responses, the input field is updated accordingly).
After the HiddenLayer inbound check completes, the policy sets the Azure OpenAI Authorization header ({{aoai-api-key}}), removes Ocp-Apim-Subscription-Key and X-Requester-Id, and records timing for the backend call.
Calling HiddenLayer Outbound (Model Output)
The outbound section reads the assistant turn from choices[0].message (chat completions shape), sends only that normalized message to /detection/v1/interactions, and applies the same Block (403) / Redact / fail-open behavior. Redaction merges modified_data.output.messages back into choices[0].message.
Timing / correlation headers (X-Correlation-ID, X-HiddenLayer-*-Ms, etc.) are added on the response for observability.
Appendix
Correlating HiddenLayer Logs with APIM Logs
The complete policy above already stores APIM’s RequestId as correlation_id and sends X-Correlation-ID on HiddenLayer requests and on the client response. That matches gateway logs without extra steps.
If you are building a smaller policy or fragment by hand, you can add the same pattern explicitly:
APIM Policy Fragments
Policy fragments are centrally managed, reusable XML code snippets that can enable consistent integration with AI Runtime across the APIM environment. For more information from Microsoft, see Reuse Policy Configurations in API Management.
It is common to maintain the inbound HiddenLayer logic (OAuth, input scan, Azure OpenAI headers) and the outbound HiddenLayer logic (output scan, timing headers) as separate fragments. That lets you reuse the HiddenLayer pieces across APIs while composing them with unrelated APIM policy (rate limiting, caching, JWT validation, transformation steps, or other backends) in the order your operation requires.
The OAuth token cache logic shown in the inbound section above can be extracted into a fragment (for example, named hiddenlayer-saas-auth) and referenced in any policy using:
Example usage in a policy: