Skip to content

Adding Cookies to a Windows Phone 7 HttpWebRequest

I just spent a couple days on this and, in the end, I didn’t really figure it out. Someone else at my work (the brilliant Rylan Barnes) showed me the workaround for it.

So… you want to add a cookie to your Windows Phone 7 Silverlight HttpWebRequest. Guess what? It sucks to be you! Or, at least, it sucked to be me because I couldn’t find anything on how to do this that worked.

I was working on a project that requires the user to authenticate and, on authentication, sends back a token (unique to that user) to be attached as a cookie for further authentication. However, when I attached the cookie and made my next request, it made that request without the authorization header. Our server said “Hey, looks like you’re not authenticated, I will now forget about that last cookie because you obviously didn’t get it. Have a new one!”

First I’m going to show you things that don’t work.

Didn’t Work: Adding An Empty Cookie Container to the Request

public void DoSomeCRUD(string userName, string pass)
{
    HttpWebRequest request = System.Net.HttpWebRequest.Create("https://myurl.com") as HttpWebRequest;
    if (HasSavedCookieContainer)
        request.CookieContainer = SavedCookieContainer();
    else 
        request.CookieContainer = new CookieContainer();
    request.Credentials = new NetworkCredential(userName, pass);
    request.BeginGetResponse(new AsyncCallback(GetMyResponse), request);
}

private void GetMyResponse(IAsyncResult MyResponseAsync)
{
    HttpWebRequest request = (HttpWebRequest)MyResponseAsync.AsyncState;
    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(MyResponseAsync);
    // this method save the cookie container to IsolatedStorage 
    // so I can attach it to the request the next time I open the app.
    SaveCookieContainer(request.CookieContainer);
}

The saving worked, the cookie container came back just as I saved it. And then… it didn’t work. It was as if the cookie didn’t exist.

Didn’t Work: Ripping The Token Out Of the “Set-Cookie” Header

public void DoSomeCRUD(string userName, string pass)
{
    HttpWebRequest request = System.Net.HttpWebRequest.Create("https://myurl.com") as HttpWebRequest;
    if (IsolatedStorageSettings.ApplicationSettings.Contains["MyToken"])
    {
        string myToken = (string)IsolatedStorageSettings.ApplicationSettings["MyToken"];
        Cookie c = new Cookie("MyCookieName", myToken, "[valid path]", "[valid domain]");
        request.CookieContainer = new CookieContainer();
        request.CookieContainer.Add(new Uri("http://myurl.com"), c);
    }
    else
        request.CookieContainer = new CookieContainer();
    request.Credentials = new NetworkCredential(userName, pass);
    request.BeginGetResponse(new AsyncCallback(GetMyResponse), request);
}

private void GetMyResponse(IAsyncResult MyResponseAsync)
{
    HttpWebRequest request = (HttpWebRequest)MyResponseAsync.AsyncState;
    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(MyResponseAsync);
    // this method looked for "Set-Cookie" information in the header
    // and the pulls out the token data by brute force and save the
    // token as a string
    if (ResponseHasSetCookieInHeader(response))
    {
        string rawToken = GetTokenFromResponse(response);
        IsolatedStorageSettings.ApplicationSettings["MyToken"] = rawToken;
        IsolatedStorageSettings.ApplicationSettings.Save();
    }
}

The save worked here too, but the same result… it was like the cookie didn’t exist.

This Worked: Adding the Cookie as a Header

Finally we added the token and the credential information as header items. This finally worked.

public void DoSomeCRUD(string userName, string pass)
{
    HttpWebRequest request = System.Net.HttpWebRequest.Create("https://myurl.com") as HttpWebRequest;
    if (IsolatedStorageSettings.ApplicationSettings.Contains["MyToken"])
        request.Headers["Cookie"] = "MyTokenName=" + (string)IsolatedStorageSettings.ApplicationSettings["MyToken"];
        
    request.Headers["Authentication"] = "Basic " + Convert.ToBase64String(StringToAscii(userName, pass));
    request.BeginGetResponse(new AsyncCallback(GetMyResponse), request);
}

private void GetMyResponse(IAsyncResult MyResponseAsync)
{
    HttpWebRequest request = (HttpWebRequest)MyResponseAsync.AsyncState;
    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(MyResponseAsync);
    // this method looks for "Set-Cookie" information in the header
    // and the pulls out the token data, saving it to Isolated Storage
    if (ResponseHasSetCookieInHeader(response))
    {
        string rawToken = GetTokenFromResponse(response);
        IsolatedStorageSettings.ApplicationSettings["MyToken"] = rawToken;
        IsolatedStorageSettings.ApplicationSettings.Save();
    }
}

For the sake of giving credit, here is the StringToAscii method for the Authentication, tweaked from this StackOverflow answer from Hans Passant

public static byte[] StringToAscii(string userName, string pass)
{
    string s = userName + ":" + pass;
    byte[] retval = new byte[s.Length];
    for (int ix = 0; ix < s.Length; ++ix)
    {
        char ch = s[ix];
        if (ch <= 0x7f) retval[ix] = (byte)ch;
        else retval[ix] = (byte)'?';
    }
    return retval;
}