How to use APIM set-header policy to manage Set-Cookie headers

Nathan 55 Reputation points
2023-10-13T09:33:09.0233333+00:00

I have a set of backend APIs on Azure App Services behind an instance of APIM. These use the TiPMix and x-ms-routing-name cookies to control slot swaps. Unfortunately, they set these cookies with the wrong domain name, and I'd like to rewrite the cookies using APIM. I'm also running APIM at a /api route managed by Front Door, so I might as well rewrite the cookie paths at the same time.

Ignoring the domain rewrite for now (which is just a Regex), I want to do something like this:

<!--Fix any cookies by rewriting their path -->
<set-header name="Set-Cookie" exists-action="override">
   <value>@{
      var headerValue = context.Response.Headers.GetValueOrDefault("Set-Cookie", "");
      var inputCookies = headerValue.Split(',');
      var outputCookies = new List<string>();
      foreach (var inputCookie in inputCookies) {
         outputCookies.Add(inputCookie.Replace("path=/;", "path=/api;"));
      }
      return outputCookies;
   }</value>
</set-header>

However, GetValueOrDefault concatenates all the Set-Cookie headers into one, split by comma. This is bad for cookies which contain an expiry date containing a comma, so I can't string.Split to get each cookie. After rewriting, I also can't figure out how to make set-header output multiple values: returning a comma-separated string results in a CSV output in the header value, not multiple header-value pairs.

The code above doesn't work because outputCookies can't be a list.

set-header docs don't have enough detail to figure this out, so I've raised a GitHub issue on the docs explaining the same problem.

Could anyone explain how to accomplish this with some example code please?

Azure API Management
Azure API Management
An Azure service that provides a hybrid, multi-cloud management platform for APIs.
1,782 questions
{count} votes

Accepted answer
  1. MuthuKumaranMurugaachari-MSFT 22,156 Reputation points
    2023-10-17T13:58:42.0866667+00:00

    Nathan Thanks for your patience. Please find the answers below:

    1. Make sure that the backend API is returning the headers as multiple header values instead of comma separated values. If the backend itself returns as comma separated values (i.e. single header), it is not possible to loop through with the split.
    2. I used set-header policy (code snippet below) in the outbound section as described in the doc and able to validate that it indeed returned as multiple header values (yes, this only applies to standardized headers such as Cookie, Set-Cookie) to the browser.
    <outbound>
            <set-header name="Set-Cookie" exists-action="override">
                <value>Cookie1=Value1;Path=/;Expires=Wed, 21 Oct 2015 07:28:00 GMT;</value>
                <value>Cookie2=Value3;Path=/;Expires=Wed, 21 Oct 2015 07:28:00 GMT;</value>
                <value>Cookie3=Value3;Path=/;Expires=Wed, 21 Oct 2015 07:28:00 GMT;</value>
            </set-header>
            <base />
        </outbound>
    

    Output:
    User's image

    1. You are right, GetValueOrDefault returns comma-separated response header values as described in the doc. Instead, you can follow the below code snippet to loop through the cookies to generate a string (comma separated values) and then assign it to Set-header. You can even use split inside the for loop based on your scenario. Note: context.Response.Headers returns IReadOnlyDictionary and hence you need to use Set-Header to override the values.
    <set-header name="Set-Cookie" exists-action="override">
                <value>@{
                if (context.Response.Headers["Set-Cookie"] != null)
                {
                    var outputCookies = new List<string>();
                    for (var i = 0; i < context.Response.Headers["Set-Cookie"].Count(); i++)
                    {
                        outputCookies.Add(context.Response.Headers["Set-Cookie"][i].Replace("Path=/;", "Path=/api;"));
                    }
                    return String.Join(",",outputCookies);
                }
                return "";
            }</value>
            </set-header>
    

    Output:

    User's image

    Currently, it is not possible to set back the header ('Set-Cookie`) as multiple header values with the dynamic collection. If you are interested in this feature, please feel free to submit via https://aka.ms/apimwish and others with similar interests can upvote it too. This will help our product team prioritize the features.

    I hope this helps with your questions and if I miss anything, please let me know.


    If you found the answer to your question helpful, please take a moment to mark it as Yes for others to benefit from your experience. Or simply add a comment tagging me and would be happy to answer your questions.


0 additional answers

Sort by: Most helpful