Alexander C.
Alexander C.

Reputation: 1191

HttpClient does not see "Set-Cookie" header

I have an MVC login form:

[HttpPost]
    public ActionResult Login(LoginViewModel viewModel)
    {
        if (viewModel.Username == "alex" && viewModel.Password == "password")
        {
            FormsAuthentication.SetAuthCookie(viewModel.Username, false);
            return RedirectToAction("Index", "Home");
        }

        return View();
    }

And Console app client that consumes MVC Login action:

private static void GetPerson()
    {
        Console.WriteLine("Username:");
        string username = Console.ReadLine();

        Console.WriteLine("Password:");
        string password = Console.ReadLine();

        using (HttpClient httpClient = new HttpClient())
        {
            HttpRequestMessage authRequest = new HttpRequestMessage();
            authRequest.Method = HttpMethod.Post;
            authRequest.RequestUri = new Uri(@"http://localhost:4391/Account/Login");
            authRequest.Content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("Username", username),
                new KeyValuePair<string, string>("Password", password)
            });

            HttpResponseMessage authResponse = httpClient.SendAsync(authRequest).Result;
            IEnumerable<string> cookieValues;
            authResponse.Headers.TryGetValues("Set-Cookie", out cookieValues);

        }
    }

Problem: authResponse.Headers.TryGetValues("Set-Cookie", out cookieValues) is not finding "Set-Cookie" header so cookieValues comes out to be "null".

I ran Fiddler for Login action in MVC and here is what I got back:

HTTP/1.1 302 Found
Cache-Control: private
Content-Type: text/html; charset=utf-8
Location: /
Server: Microsoft-IIS/8.0
X-AspNetMvc-Version: 5.1
X-AspNet-Version: 4.0.30319
Set-Cookie:   .ASPXAUTH=A6A22208AECA1F3E25B43C834BE058A5019F3A9C55AED099FFAD5B0FE7B289EC2C3F87C157B0C1ED338D1DF0A6469E6C5DE8D9DB7A99D54D992EA10F26424BA579C262B7CD247CA4193879E058A233B7A0BC98E10503440B79EB988239C43696; path=/; HttpOnly
X-SourceFiles: =?UTF-8?B?YzpcdXNlcnNcYWxleGFuZGVyXGRvY3VtZW50c1x2aXN1YWwgc3R1ZGlvIDIwMTNcUHJvamVjdHNcRm9ybVZhbHVlc0F1dGhXZWJBUElcRm9ybVZhbHVlc0F1dGhXZWJBUElcQWNjb3VudFxMb2dpbg==?=
X-Powered-By: ASP.NET
Date: Sat, 19 Apr 2014 20:09:23 GMT
Content-Length: 428

Fiddler shows that I'm getting "Set-Cookie" back but why HttpClient does not see it?

Upvotes: 2

Views: 5434

Answers (3)

Carson
Carson

Reputation: 35

I researched a lot but found one in a website of another language. The solution is to add an empty event handler for session start and end at global: protected void Session_Start(object sender, EventArgs e) { } protected void Session_End(object sender, EventArgs e) { }

Upvotes: 0

Alexander C.
Alexander C.

Reputation: 1191

Figured it out - MVC action send 2 responses back one with cookie and the second one without cookie. HttpClient shows latest response that is why it could not find "Set Cookie" header.

But!

It seems like HttpClient save cookie from the first response internally and on the request to the secured page under the same domain HttpClient automatically applies that saved cookie.

In my example if I'll connect to "localhost:4391/api/Person/1" with HttpClient I'll get unauthorized. So my goal was to go to "localhost:4391/Account/Login" with HttpClient, log in, get generated cookie then go to "localhost:4391/api/Person/1" and send that cookie but as I mentioned before HttpClient does that automatically and I dont need to extract cookie from the first request to Login page.

So code below works as needed!

private static void GetPerson()
    {
        Console.WriteLine("Username:");
        string username = Console.ReadLine();

        Console.WriteLine("Password:");
        string password = Console.ReadLine();

        HttpClient httpClient = new HttpClient();

        HttpRequestMessage authRequest = new HttpRequestMessage();
        authRequest.Method = HttpMethod.Post;
        authRequest.RequestUri = new Uri(@"http://localhost:4391/Account/Login");
        authRequest.Content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("Username", username),
                new KeyValuePair<string, string>("Password", password)
            });

        HttpResponseMessage authResponse = httpClient.SendAsync(authRequest).Result;

        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, @"http://localhost:4391/api/Person/1");
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        HttpResponseMessage response = httpClient.SendAsync(request).Result;

        if (!response.IsSuccessStatusCode)
        {
            Console.WriteLine("Username or password is incorrect");
            return;
        }

        response.Content.ReadAsAsync<Person>().ContinueWith((x) => {
                Person person = x.Result;

                Console.WriteLine("First name: {0}", person.FirstName);
                Console.WriteLine("Last name: {0}", person.LastName);
            });
    }

But going back to catching that cookie I would have been able to accomplish that if my action in the controller looked like this:

[HttpPost]
    public ActionResult Login(string username, string password) 
    {
        if (username == password) 
        {
            FormsAuthentication.SetAuthCookie(username, true);
            return new HttpStatusCodeResult(HttpStatusCode.OK);
        }
        return new HttpUnauthorizedResult();
    }

Upvotes: 1

Rishikesh
Rishikesh

Reputation: 496

Can you please try setting auth cookie like this

HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, authTicket);
Response.Cookies.Add(cookie);

Refer this article, it might shed some light. http://weblog.west-wind.com/posts/2012/Nov/29/SetCookie-Headers-getting-stripped-in-ASPNET-HttpHandlers

Upvotes: 0

Related Questions