Basic HTTP Authentication in WinRT

Written by Marc LaFleur on. Posted in Development

I’m on vacation right now, getting some much needed time with the family and preparing for my wedding at the end of the week. So what does a geek do in the midst of 6 kids and the chaos of wedding planning? Why build a Metro style app of course. Duh!

For my little application I’m working with a REST API that requires Basic HTTP Authentication. This is pretty commonplace and something I’ve done it many times in the past in web and Silverlight applications. WinRT was very similar but (as with everything in WinRT) has its own nuances.

If you’re using WinRT to call REST APIs (and honestly, who isn’t?) you will quickly become familiar the HttpClient class. It is very similar to the older WebClient and it pretty straightforward to use (and very clean thanks to the absolutely awesome await keyboard in .NET 4.5).

private async void HttpClientCall()

{

HttpClient httpClient = new HttpClient();

HttpResponseMessage response = await httpClient.GetAsync("http://yoursitehere/");

string responseAsString = await response.Content.ReadAsStringAsync();

}

In order to pass along the authentication we’ll need to add a AuthenticationHeaderValue. This took a little noodling to figure out so hopefully this saves you a bit of time. Basic HTTP authentication is handled by passing “username:password” in the header. In order to do this I needed to create a new AuthenticationHeaderValue with “basic” for the scheme and “username:password” for the value. This gets added to my HttpClient so that every call includes the Authentication information. To do that I created a method called CreateBasicHeader that generates what I need and then call that from inside my original method.

private async void HttpClientCall()
{
    HttpClient httpClient = new HttpClient();

    // Assign the authentication headers
    httpClient.DefaultRequestHeaders.Authorization = CreateBasicHeader("username", "password");

    HttpResponseMessage response = await httpClient.GetAsync("http://yoursitehere/");
    string responseAsString = await response.Content.ReadAsStringAsync();
}

public AuthenticationHeaderValue CreateBasicHeader(string username, string password)
{
    byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(username + ":" + password);
    return new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
} 

As it happens, the particular API I’m calling wants the password in an MD5 Hash rather than plain text. Luckily there was a great sample that showed how to do this. The only change I made was to use EncodeToHexString rather than EncodeToBase64String.

Here is the full sample:

private async void HttpClientCall()
{
    // Create a client
    HttpClient httpClient = new HttpClient();

    // Assign the authentication headers
    httpClient.DefaultRequestHeaders.Authorization = CreateBasicHeader("username", "password");

    // Call out to the site
    HttpResponseMessage response = await httpClient.GetAsync("http://yoursitehere/");

    // Just as an example I'm turning the response into a string here
    string responseAsString = await response.Content.ReadAsStringAsync();
}

public AuthenticationHeaderValue CreateBasicHeader(string username, string password)
{
    password = SampleHashMsg("MD5", password);
    byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(username + ":" + password);
    return new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
}

public String SampleHashMsg(String strAlgName, String strMsg)
{
    // Convert the message string to binary data.
    IBuffer buffUtf8Msg = CryptographicBuffer.ConvertStringToBinary(strMsg, BinaryStringEncoding.Utf8);

    // Create a HashAlgorithmProvider object.
    HashAlgorithmProvider objAlgProv = HashAlgorithmProvider.OpenAlgorithm(strAlgName);

    // Demonstrate how to retrieve the name of the hashing algorithm.
    String strAlgNameUsed = objAlgProv.AlgorithmName;

    // Hash the message.
    IBuffer buffHash = objAlgProv.HashData(buffUtf8Msg);

    // Verify that the hash length equals the length specified for the algorithm.
    if (buffHash.Length != objAlgProv.HashLength)
    {
        throw new Exception("There was an error creating the hash");
    }

    // Convert the hash to a string (for display).
    String strHashBase64 = CryptographicBuffer.EncodeToHexString(buffHash);

    // Return the encoded string
    return strHashBase64;
}

Update: I always try to remember to include the namespaces involved but it slipped my mind with this post. The following is the usings you’ll need for the above code:

using System.Net.Http;
using System.Net.Http.Headers;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;

Tags: , , ,

Trackback from your site.

Comments (12)

  • Basic HTTP Authentication in WinRT - Marc LaFleur

    |

    [...] Basic HTTP Authentication in WinRT I’m on vacation right now, getting some much needed time with the family and preparing for my wedding at the end of the week. So what does a geek do in the midst of 6 kids and the chaos of wedding planning? Why build a Metro style app of course. Duh! For my little application I’m working with a REST API that requires Basic HTTP Authentication. This is pretty commonplace and something I’ve done it many times in the past in…Read More [...]

    Reply

  • ddoldo

    |

    I am trying to use this code with Windows 8 RTM and I cannot get it to work. Have you tried with it with RTM. I am not sure what I am doing wrong.

    public static AuthenticationHeaderValue CreateBasicHeader(string username, string password)
    {
    byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(username + “:” + password);
    return new AuthenticationHeaderValue(“Basic”, Convert.ToBase64String(byteArray));
    }
    public static async Task HttpClientCall()
    {
    // Create a client
    HttpClient httpClient = new HttpClient();

    // Assign the authentication headers
    httpClient.DefaultRequestHeaders.Authorization = CreateBasicHeader(AccountKey, AccountKey);

    // Call out to the site
    HttpResponseMessage response = await httpClient.GetAsync(“https://api.datamarket.azure.com/Bing/SearchWeb/Web?Query=test”);

    // Just as an example I’m turning the response into a string here
    string responseAsString = await response.Content.ReadAsStringAsync();
    }

    Reply

    • Marc LaFleur

      |

      My little test app seems to work fine. What are you getting for errors?

      Reply

  • kaysha

    |

    Hi Marc,

    thanks for your this excellent tutorial.

    I have one question:

    I am trying to do the web authentication using following code.

    HttpClient httpClient4 = new HttpClient();

    httpClient4.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(“Basic”, usernamePassword);

    httpClient4.DefaultRequestHeaders.Add(“user-Agent”, “harvestauthentication.cs”);

    HttpResponseMessage response5 = await httpClient4.GetAsync(“https://mywebsite/projects”);

    string responseAsString = await response5.Content.ReadAsStringAsync();

    I need to paas the header type(user-agent and content-type). how can i pass them.

    please could you help me with this?
    I would really appreciated it.

    Thanks

    Reply

  • Kaysha

    |

    Hi Marc,

    thanks for your reply.

    I am getting an error “An exception of type ‘System.InvalidOperationException’ occurred in System.Net.Http.dll but was not handled in user code

    Additional information: Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.”

    see my code below, if you have any further comments:

    HttpClient httpClient5 = new HttpClient();
    httpClient5.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(“Basic”, usernamePassword);

    // Add a new Request Message
    HttpRequestMessage requestMessage3 = new HttpRequestMessage(HttpMethod.Put, “https://mycompany.harvestapp.com/projects”);

    // Add our custom headers
    requestMessage3.Headers.Add(“Content-Type”, “application/xml”);
    requestMessage3.Headers.Add(“User-Agent”, “harvest.cs”);

    // Send the request to the server
    HttpResponseMessage response6 = await httpClient5.SendAsync(requestMessage3);

    // Just as an example I’m turning the response into a string here
    string responseAsString2 = await response6.Content.ReadAsStringAsync();

    Reply

  • Marc LaFleur

    |

    I’ve updated the post, there was an error in the sample I posted. Content-Type is a Content Header so it must be defined under Content.

    requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue(“MimeType”);

    Reply

  • Kaysha

    |

    Thanks for the update.

    It is working now :)

    sorry for being a pain.
    Not getting any result back from the API.

    Actually i am just trying to use the same for see the link:
    https://github.com/harvesthq/harvest_api_samples/blob/master/harvest_api_sample.cs

    i think something going wrong i am getting response back from the API but it is saying “You are using an unsupported browser” and “Please enable JavaScript”.

    Any idea why?
    i really appriciate your help…

    Reply

  • Marc LaFleur

    |

    Not a pain, I’m here to help.

    Try commenting out the User-Agent. The User Agent tells the server what kind of “browser” you are. Maybe removing it will allow it to work as expected?

    Reply

  • Kaysha

    |

    thanks for your help!

    I have tried commenting out the User-Agent but still te same problem.
    Have you had a chance to look at the code in the link?
    In case you may find something which I cann’t?
    any other idea?

    Reply

Leave a comment

Follow

Get every new post delivered to your Inbox

Join other followers: