azureoauth-2.0openid-connectpolicyapim

Azure APIm policy not returning a response


I am attempting to implement a simple Azure APIm policy that enforces Entra ID OIDC, and then calls a backend service using a proprietary token. In summary the policy does the following:

Inbound Policy

Backend Policy

I can see that all of these steps work correctly, using APIm tracing - however the payload being returned to the caller is always empty.

It is unclear if I need to do anything with the outbound policy to ensure that the response from teh backend service is returned.

Any assistance would be gratefully received

Full policy can be seen below.

<policies>
    <inbound>
        <set-variable name="clientID" value="{{essential-client-id}}" />
        <set-variable name="clientSecret" value="{{essential-client-secret}}" />
        <validate-azure-ad-token tenant-id="{{essential-api-tenant-id}}" output-token-variable-name="jwt" failed-validation-error-message="Missing Entra ID OAuth 2.0 token">
            <client-application-ids>
                <!--application-id>{{essential-api-application-id}}</application-id-->
                <application-id>{{mg4v-application-id}}</application-id>
            </client-application-ids>
            <audiences>
                <audience>api://{{essential-api-application-id}}</audience>
            </audiences>
        </validate-azure-ad-token>
        <send-request ignore-error="true" timeout="20" response-variable-name="bearerToken" mode="new">
            <set-url>{{essential-api-domain}}/api/oauth/token</set-url>
            <set-method>POST</set-method>
            <set-header name="Content-Type" exists-action="override">
                <value>application/json</value>
            </set-header>
            <set-header name="x-api-key" exists-action="override">
                <value>{{essential-api-key}}</value>
            </set-header>
            <!--  We do not want to expose our APIM subscription key to the backend API  -->
            <set-header name="Ocp-Apim-Subscription-Key" exists-action="delete" />
            <set-body>@($"{{\"grantType\": \"password\", \"username\": \"{(string)context.Variables["clientID"]}\", \"password\": \"{(string)context.Variables["clientSecret"]}\" }}")</set-body>
        </send-request>
        <base />
    </inbound>
    <!-- Control if and how the requests are forwarded to services  -->
    <backend>
        <send-request mode="new" response-variable-name="response" timeout="10" ignore-error="false">
            <set-url>{{essential-api-domain}}api/essential-core/v1/repositories/{{essential-repo-id}}/applications</set-url>
            <set-method>GET</set-method>
            <set-header name="Authorization" exists-action="override">
                <value>@($"Bearer {(String)((IResponse)context.Variables["bearerToken"]).Body.As<JObject>().SelectToken("bearerToken")}")</value>
            </set-header>
            <set-header name="x-api-key" exists-action="override">
                <value>{{essential-api-key}}</value>
            </set-header>
            <set-header name="Content-Type" exists-action="override">
                <value>application/json</value>
            </set-header>
        </send-request>
    </backend>
    <outbound>
        <base/>
    </outbound>
    <!-- Handle exceptions and customize error responses  -->
    <on-error>
        <set-header name="ErrorSource" exists-action="override">
            <value>@(context.LastError.Source)</value>
        </set-header>
        <set-header name="ErrorReason" exists-action="override">
            <value>@(context.LastError.Reason)</value>
        </set-header>
        <set-header name="ErrorMessage" exists-action="override">
            <value>@(context.LastError.Message)</value>
        </set-header>
        <set-header name="ErrorScope" exists-action="override">
            <value>@(context.LastError.Scope)</value>
        </set-header>
        <set-header name="ErrorSection" exists-action="override">
            <value>@(context.LastError.Section)</value>
        </set-header>
        <set-header name="ErrorPath" exists-action="override">
            <value>@(context.LastError.Path)</value>
        </set-header>
        <set-header name="ErrorPolicyId" exists-action="override">
            <value>@(context.LastError.PolicyId)</value>
        </set-header>
        <set-header name="ErrorStatusCode" exists-action="override">
            <value>@(context.Response.StatusCode.ToString())</value>
        </set-header>
        <base />
    </on-error>
</policies>

Solution

  • Thanks n___dv - solution required a bit of additional work

        <outbound>
            <set-body>@($"{((IResponse)context.Variables["response"]).Body.As<JObject>().ToString()}")</set-body>
            <base/>
        </outbound>