How configure Azure API Management for CORS

Viewed 7198

I have create an Azure API Management Service and connected my APIs. I added CORS policies to them.

enter image description here

I checked the Calculate effective policy and the result is this policy

enter image description here

<policies>
    <inbound>
        <!-- base: Begin Product scope -->
        <!-- base: Begin Global scope -->
        <cors allow-credentials="true">
            <allowed-origins>
                <origin>https://developer.mydomain.com</origin>
            </allowed-origins>
            <allowed-methods preflight-result-max-age="300">
                <method>*</method>
            </allowed-methods>
            <allowed-headers>
                <header>*</header>
            </allowed-headers>
            <expose-headers>
                <header>*</header>
            </expose-headers>
        </cors>
        <!-- base: End Global scope -->
        <!-- base: End Product scope -->
        <cors>
            <allowed-origins>
                <origin>*</origin>
            </allowed-origins>
            <allowed-methods>
                <method>GET</method>
                <method>POST</method>
            </allowed-methods>
        </cors>
    </inbound>
    <backend>
        <!-- base: Begin Product scope -->
        <!-- base: Begin Global scope -->
        <forward-request />
        <!-- base: End Global scope -->
        <!-- base: End Product scope -->
    </backend>
    <outbound />
    <on-error />
</policies>

enter image description here

If I call the API with C#, it is working. Then, I created a simple JavaScript to call the API but there is no way to avoid CORS. I tried different JavaScript

<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    </head>
    <body>
        <script>
        var url = '';
        var headerKey = 'subscription-Key';
        var headerValue = 'e1e21';

        $.ajax({
            url: url,
            beforeSend: function(xhrObj){
                // Request headers
                xhrObj.setRequestHeader("Origin","https://www.puresourcecode.com/");
                xhrObj.setRequestHeader("Access-Control-Allow-Origin","https://www.puresourcecode.com/");
                xhrObj.setRequestHeader("Access-Control-Request-Method","GET");
                xhrObj.setRequestHeader("Access-Control-Allow-Credentials","true");
                xhrObj.setRequestHeader("Access-Control-Request-Headers","X-Custom-Header");
                xhrObj.setRequestHeader("Access-Control-Allow-Headers","Origin, Content-Type, Accept, Authorization, X-Request-With");
                xhrObj.setRequestHeader(headerKey,headerValue);
            },
            type: "GET",
            contentType: "application/json; charset=utf-8",
        })
        .done(function(data) {
            alert("success");
        })
        .fail(function() {
            alert("error");
        });

        // jQuery preflight request
        $.ajax({
            type: "GET",
            headers: {headerKey: headerValue},
            url: url
        }).done(function (data) {
            console.log(data);
        });
        
        // XMLHttpRequest preflight request
        var xhr = new XMLHttpRequest();
        xhr.open("GET", url, true);
        xhr.setRequestHeader(headerKey, headerValue);
        xhr.onload = function () {
            console.log(xhr.responseText);
        };
        xhr.send();
        
        // Fetch preflight request
        var myHeaders = new Headers();
        myHeaders.append(headerKey, headerValue);
        fetch(url, {
            headers: myHeaders
        }).then(function (response) {
            return response.json();
        }).then(function (json) {
            console.log(json);
        });
        </script>
    </body>
</html>

All of them are failing because of CORS. I tried to add preflight-result-max-age="300" and also specified the allowed-headers like the one I use to pass the subscription key without success. I also tried to copy this file in my server with the same error.

enter image description here

As origin I set * because I thought in this way every request for every URL is accepted but obviously not.

What is the correct settings to apply in the Azure API Management to avoid CORS?

1 Answers

I think to issue happens when you enable the Developer portal. Then, in the configuration for the portal, you enable CORS. At this point, Azure automatically adds a global policy to the API Management Service but you don't know that.

<policies>
    <inbound>
        <!-- base: Begin Global scope -->
        <cors allow-credentials="true">
            <allowed-origins>
                <origin>https://developer.mydomain.com</origin>
            </allowed-origins>
            <allowed-methods preflight-result-max-age="300">
                <method>*</method>
            </allowed-methods>
            <allowed-headers>
                <header>*</header>
            </allowed-headers>
            <expose-headers>
                <header>*</header>
            </expose-headers>
        </cors>
        <!-- base: End Global scope -->
    </inbound>
</policies>

Happily, you configure CORS in your API and when you try to call them from JavaScript, you are facing the CORS error.

If you open the CORS configuration in the Azure portal you can see something like that:

<policies>
    <inbound>
        <base />
        <cors>
            <allowed-origins>
                <origin>*</origin>
            </allowed-origins>
            <allowed-methods preflight-result-max-age="300">
                <method>GET</method>
                <method>POST</method>
            </allowed-methods>
            <allowed-headers>
                <header>*</header>
                <header />
            </allowed-headers>
            <expose-headers>
                <header>*</header>
            </expose-headers>
        </cors>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

My understanding is the portal combine the base configuration with yours. So, like in Active Directory the more restricted policy is applying. That means in my example, only the Developer Portal can call the APIs without CORS issue.

Solution

Delete <base /> under <inbound> and save.

Related