Forum

Please or Register to create posts and topics.

How configure Azure API Management for CORS

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

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

<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>

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.

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?

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.