Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Building a Twitter client for Windows Phone - OAuth client & basic infrastructure

DZone's Guide to

Building a Twitter client for Windows Phone - OAuth client & basic infrastructure

· Mobile Zone
Free Resource

Get gorgeous, multi-touch charts for your iOS application with just a few lines of code.

Twitter is now officially integrated in the Windows Phone OS as a part of the Mango update. However, it is always possible to extend the existing user experience, and that is exactly why I am going to show you how it is possible to build a full-fledged Twitter client for Windows Phone from scratch.

The first thing that you need to do is register a Twitter application. Although there are Twitter endpoints that are open (e.g. public timeline for a specific user), some interactive capabilities, like status updates or image uploads require authentication and direct association with an app that is known to Twitter. To register a new application, you should already have an active Twitter account. Head over here now:

https://dev.twitter.com/apps

You will see a list of applications currently registered by you. If you haven't used this before, then most likely the list will be empty.

Click on Create a new application and fill out the fields for your application.

In my case, I named the application MangoTree (you see where I got this, right?). And before it is asked - yes, I will release the application in the Marketplace once we are done with this project. You are basically following (read: shadowing) my development steps with this project.

By default, new applications are created with read-only permissions. Obviously, for a Twitter client this is unacceptable unless you are simply creating a reader. To change this, head over to Settings for your application and change Access to Read, Write and Access direct messages. Once you saved the changes, take a look at what information you have available, that is related to the application (go back to the Details tab).

OAuth settings is the most important part here. Make sure that Consumer Key and Consumer Secret are available in your application, but are not available to the user - you will only use those internally.

This is where we begin our Windows Phone application. Create a new C#-based standard Windows Phone application in Visual Studio, and set the target platform to Windows Phone 7.1, because we will use some Mango capabilities later on.

Create a new folder called Twitter in your solution. Create a new class called AuthConstants. Mark that class as static and create two static string constants - ConsumerKey and ConsumerSecret. These will be reused later in the application. I am marking them as constants because both values are never changing.

 

namespace MangoTree.Twitter
{
    public static class AuthConstants
    {
        public const string ConsumerKey = "";
        public const string ConsumerSecret = "";
    }
}

Obviously, here you need to insert your own consumer key and consumer secret. I decided to keep these here for easier access. Another choice would be using an XML/JSON file and then parsing the values at runtime, but that would be a bit more resource consuming, and given the fact that none of the values I am setting to be a constant change often (if at all), we can keep them in the code-behind.

Another class that needs to be created is UrlConstants. That's where I will reference the URL endpoints that I am going to use in various parts of the application. Once again - you can store them in an XML file and then parse, but you already know the reason why I am not doing that. It is also a static class and at this moment it holds two constants - RequestToken and AccessToken.

namespace MangoTree.Twitter
{
    public static class UrlConstants
    {
        // Auth
        public const string RequestToken = "https://api.twitter.com/oauth/request_token";
        public const string AccessToken = "https://api.twitter.com/oauth/authorize";
    }
}

You might be wondering - why am I not using the Uri class instead? Simple. Because from time to time I might need to read the raw string and I would rather work with the value itself than take it out of an Uri instance.

Now it's time to ask the user to authorize the application. In order to do this, I built the initial authorization screen to be pretty easy to navigate through.

The XAML structure is the following:

<phone:PhoneApplicationPage 
    x:Class="MangoTree.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="False">

    <StackPanel x:Name="LayoutRoot" Background="Transparent">
        <TextBlock Text="Step 1:" Style="{StaticResource PhoneTextLargeStyle}" Margin="10,0,0,0"></TextBlock>
        <TextBlock Text="Acquire a PIN code to authorize MangoTree to be used with your account." TextWrapping="Wrap" Style="{StaticResource PhoneTextTitle3Style}" Margin="10,0,0,0"></TextBlock>
        <Button x:Name="btnAcquire" Content="Acquire PIN" Width="220" HorizontalAlignment="Left"></Button>

        <TextBlock Text="Step 2:" Style="{StaticResource PhoneTextLargeStyle}" Margin="10,30,0,0"></TextBlock>
        <TextBlock Text="Enter the previously acquired PIN code." TextWrapping="Wrap" Style="{StaticResource PhoneTextTitle3Style}" Margin="10,0,0,0"></TextBlock>
        <TextBox x:Name="txtPIN" Width="480" HorizontalAlignment="Left"></TextBox>

        <TextBlock Text="Step 3:" Style="{StaticResource PhoneTextLargeStyle}" Margin="10,30,0,0"></TextBlock>
        <TextBlock Text="Confirm your PIN code." TextWrapping="Wrap" Style="{StaticResource PhoneTextTitle3Style}" Margin="10,0,0,0"></TextBlock>
        <Button x:Name="btnConfirm" Content="Confirm PIN" Width="220" HorizontalAlignment="Left"></Button>
    </StackPanel>
</phone:PhoneApplicationPage>

It's quite simple, yet efficient. We'll improve the UI later on - now we need the basic functionality up and running. 

You might be wondering - what exactly is a PIN and why do I need it? Given the current authentication flow for Twitter, it will be much easier if I would use a PIN to authorize the user than use callbacks, as this goes with web applications. In fact, this would be the only efficient way to authorize the user.

When the user clicks on Acquire PIN, I will request an application token and will redirect the user to the official Twitter authentication page, where the user will be able to review the permissions I am requesting in the context of MangoTree and enter his credentials in case he agrees my application to be linked to his account.

Let's build the connection infrastructure. In your Twitter folder, create a class called OAuthClient. This will be the central connection point for everything that is done in this application. Take a look:

public class OAuthClient
{
    public void PerformRequest(Dictionary<string, string> parameters, string url, string consumerSecret, string token, byte type)
    {
        string OAuthHeader = OAuthClient.GetOAuthHeader(parameters, "POST", url, consumerSecret, token);

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.Method = "POST";
        request.Headers["Authorization"] = OAuthHeader;

        request.BeginGetResponse(new AsyncCallback(GetToken), request);
    }

    public static void GetToken(IAsyncResult result)
    {

        HttpWebRequest request = (HttpWebRequest)result.AsyncState;
        HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);

        using (StreamReader reader = new StreamReader(response.GetResponseStream()))
        {
            string[] data = reader.ReadToEnd().Split(new char[] { '&' });
            int index = data[0].IndexOf("=");
            string token = data[0].Substring(index + 1, data[0].Length - index - 1);
            Debug.WriteLine("TOKEN OBTAINED");

            WebBrowserTask task = new WebBrowserTask();
            task.Uri = new Uri("http://api.twitter.com/oauth/authorize?oauth_token=" + token);
            task.Show();
        }
    }

    public static string GetOAuthHeader(Dictionary<string, string> parameters, string httpMethod, string url, string consumerSecret, string tokenSecret)
        {
            parameters = parameters.OrderBy(x => x.Key).ToDictionary(v => v.Key, v => v.Value);

            string concat = string.Empty;

            string OAuthHeader = "OAuth ";
            foreach (string k in parameters.Keys)
            {
                concat += k + "=" + parameters[k] + "&";
                OAuthHeader += k + "=" + "\"" + parameters[k] + "\", ";
            }

            concat = concat.Remove(concat.Length - 1, 1);
            concat = StringHelper.EncodeToUpper(concat);

            concat = httpMethod + "&" + StringHelper.EncodeToUpper(url) + "&" + concat;

            byte[] content = Encoding.UTF8.GetBytes(concat);

            HMACSHA1 hmac = new HMACSHA1(Encoding.UTF8.GetBytes(consumerSecret + "&" + tokenSecret));
            hmac.ComputeHash(content);

            string hash = Convert.ToBase64String(hmac.Hash);
            hash = hash.Replace("-", "");

            OAuthHeader += "oauth_signature=\"" + StringHelper.EncodeToUpper(hash) + "\"";

            return OAuthHeader;
        }
}

There are three things going on here at the moment. I have a PerformRequest method, that is the initializer for all requests going through it. Pay close attention to what I am passing to that method - an instance of Dictionary, that stores the parameters that are used to build the OAuth authorization headers.

GetOAuthHeader is the core method to build to organize the headers in a correct sequence - I am arranging correct keys and values alphabetically. It also creates the signature (HMAC-SHA1) for the concatenated, correctly arranged string with all parameters. In the context of this method, I am using StringHelper.EncodeToUpper - a reference to a method that selects encodes parts of the concatenated strings and transforms the encoded alpha-based characters to uppercase letters. That's because for some reason, Twitter's OAuth process throws an error when those characters are not uppercase.

The EncodeToUpper method should be created in the context of a static StringHelper class, that is created inside a new Utility folder.

namespace MangoTree.Utility
{
    public static class StringHelper
    {
        public static string EncodeToUpper(string raw)
        {
            raw = HttpUtility.UrlEncode(raw);
            return Regex.Replace(raw, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper());
        }
    }
}

Now back to OAuthClient. Last but not least, I have the asynchronous callback that is invoked once the token is received. Notice that I am taking it and then passing to a WebBrowserTask that will show the official Twitter authorization page later on.

Congratulations - you now have the essentials and are ready to proceed with more Twitter activity.

.Net developers: use Highcards, the industry's leading interactive charting library, without writing a single line of JavaScript.

Topics:

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}