Search code examples
c#cookiessetcookiedomaincontroller

Cookie for domain not being used for subdomains


I use HttpClient in my app to send my user/password to a service that returns some cookies that I can later use for all my other requests. The service is located at https://accounts.dev.example.com/login and returns two cookies that have Domain=.dev.example.com. The issue I'm finding is that, in some machines (Windows Domain Controllers), these cookies are not being used when I request resources in subdomains like https://accounts.dev.example.com/health-check, but according to the MDN docs a cookie for a domain can be used for requesting resources to subdomains:

Domain= Optional

Specifies those hosts to which the cookie will be sent. If not specified, defaults to the host portion of the current document location (but not including subdomains). Contrary to earlier specifications, leading dots in domain names are ignored. If a domain is specified, subdomains are always included.

Do you know how to properly configure HttpClient to pass the domain cookies to subdomain requests?

A bit more of details:

The cookies returned by my authentication service at https://accounts.dev.example.com/login look like this in the HTTP headers:

Set-Cookie: AK=112233;Version=1;Domain=.dev.example.com;Path=/;Max-Age=5400;Secure;HttpOnly, 
Set-Cookie: AS=445566;Version=1;Domain=.dev.example.com;Path=/;Max-Age=5400;Secure;HttpOnly, 

Then I can query C#'s CookieContainer with either of these calls in normal workstations:

cookies.GetCookies("https://accounts.dev.example.com")
cookies.GetCookies("https://dev.example.com")

Both of which will return the 2 cookies like:

$Version=1; AK=112233; $Path=/; $Domain=.dev.example.com
$Version=1; AS=445566; $Path=/; $Domain=.dev.example.com

But in the other machines (the Domain Controller's) the first call will return an empty list, while the second will return the 2 cookies.

Why this difference on the behaviour of CookieContainer.GetCookies depending on which machine is running the code?

My workstations are using Microsoft Windows 10 Home Single Language (.Net 4.0.30319.42000) and the DCs are using Microsoft Windows Server 2012 R2 Datacenter (.Net 4.0.30319.36399).

The code

This is a modified version of my code:

public static async Task<string> DoAuth(CookieContainer cookies,
                                        Dictionary<string, string> postHeaders,
                                        StringContent postBody)
{
    try
    {
        using (var handler = new HttpClientHandler())
        {
            handler.CookieContainer = cookies;
            using (var client = new HttpClient(handler, true))
            {
                foreach (var key in postHeaders.Keys)
                    client.DefaultRequestHeaders.Add(key, postHeaders[key]);

                var response = await client.PostAsync("https://accounts.dev.example.com/login", postBody);
                response.EnsureSuccessStatusCode();
                
                // This line returns 0 in Domain Controllers, and 2 in all other machines
                Console.Write(cookies.GetCookies("https://accounts.dev.example.com").Count);

                return await response.Content.ReadAsStringAsync();
            }
        }
    }
    catch (HttpRequestException e)
    {
        ...
        throw;
    }
}

Solution

  • As I couldn't find an answer to this (not in TechNet either), I decided to go with the following solution, which works, but not sure if there is a proper way of solving the issue:

    foreach (Cookie cookie in cookies.GetCookies(new Uri("https://dev.example.com")))
    {
        cookies.Add(new Uri("https://accounts.dev.example.com"), new Cookie(cookie.Name, cookie.Value, cookie.Path, ".accounts.dev.example.com"));
    }
    

    So, I'm duplicating the cookie for each one of the subdomains that my app should send these cookies to.