Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

TwitterRT - The Design

4.00/5 (1 vote)
22 Oct 2012CPOL7 min read 6.6K  
This post describes the inner workings of TwitterRT and how it fulfills the Twitter OAUTH API.

This post describes the inner workings of TwitterRT and how it fulfills the Twitter OAUTH API. You do not need to read this if you are just using TwitterRT and do not really care how it works.

Other posts in this series:

There are three major parts to issuing a tweet on behalf of your user:

  • Register your application with Twitter.
    This is a bit involved and not explained in this post.
    Instead, first read Posting To Twitter from Metro in C#.
  • Signing in to Twitter from your application.
    This is more complicated and is described in 3 steps below.
  • Posting Tweets.
    This is a pretty easy and described at the end of this post.

Signing In to Twitter

The authoritative description of what needs to be done to sign in to Twitter is very well described in Twitter’s very own Implementing Sign in with Twitter. Their document outlines three steps. It would be best if you kept both their document and this post open and side-by-side.

The days of asking your user for their Twitter name and password are over. Life on the web does not work that way anymore. Your application will never know the user’s password. So go ahead and delete that XAML you created that prompts the user for that information. It is useless to you.

We are now in the world of OAUTH. That means you go through some complicated process to get permission to interact with Twitter on the user’s behalf. If the user changes their Twitter password, you don’t care because your application keeps on working just fine. However, the user can revoke your applications permission at any time using the Twitter website.

The title of this section is “Signing in to Twitter”. That is a bit misleading. Your application only needs to “Sign in” once, not every session. When you perform the one-time sign in, you get a special access token. You will save that token on the user’s computer. Then, when your application runs another day, you can use that token to Tweet again. The token never expires.

So basically, we are saying, “Hey Twitter, I want to authorize my application to post on behalf of whoever is running my application, but I don’t know their user name or password (and I don’t care).

Again, there are three steps to obtaining the token:

Step 1: Obtaining a Request Token

Step 1 is letting Twitter know we want to start the process of signing in the user and obtaining a token with which we can tweet.

C#
// Step 1: Obtaining a request token
async Task<TwitterRtPostResults> Step1()
{
    var header = new TwitterRtDictionary();
    header.Add("oauth_callback", Uri.EscapeDataString(_callbackUrl));
    header.Add("oauth_consumer_key", _consumerKey);
    header.Add("oauth_nonce", GenerateNonce());
    header.Add("oauth_signature_method", _signatureMethod);
    header.Add("oauth_timestamp", GenerateSinceEpoch());
    header.Add("oauth_version", _oauthVersion);
    return await PostData(_requestTokenUrl, header);
    // should contain oauth_token, oauth_token_secret, and oauth_callback_confirmed
}

In TwitterRT, we do this by first creating a TwitterRtDictionary. The dictionary is simply a SortedDictionary<String, String> with a few special functions that really reduce the complexity of the rest of the code. Then we build a header in accordance with what Twitter requires. The callback URL and the consumer key are provided to the constructor of TwitterRT (and described in Posting To Twitter from Metro in C#). The other parameters are pretty trivial.

The PostData function is the most tricky part of the TwitterRT library, and it will be described later. For now, we just need to know that PostData will navigate to https://api.twitter.com/oauth/request_token, and send along a header that contains a bunch of parameters. PostData then gathers up the response from Twitter and places it in this handy class called TwitterRtPostResults.

C#
public class TwitterRtPostResults
{
    public enum EStatus
    {
        Success = 0,
        Canceled = 1,
        Error = 2,
    }

    public EStatus Status { get; set; }
    public String Description { get; set; }
    public TwitterRtDictionary Dictionary { get; set; }
}

What we are specifically looking for in the response is a parameter called “oauth_token” (in the Dictionary). No, this is not the token that allows us to tweet yet. We are a long way away from having that, but we are ready for step 2.

Step 2: Redirecting the User

Step 2 is the step where we pop up a Twitter webpage that asks the user to log in with their own user name and password. They also have to indicate that they will allow our application to tweet on their behalf. When this webpage is open, our application “looks the other way” while the user types in their password.

TwitterAuthorization

Metro has a very nice function that opens up a pop-up webpage. It is called AuthenticateAsync. All we pass it is the token we got from step 1. We do not have to use AuthenticateAsync, but could open our own popup. This is so much nicer though.

C#
// Step 2: Redirecting the user
async Task<twitterrtpostresults> Step2(String oauthToken)
{
    try
    {
        var url = _authorizeUrl + "?oauth_token=" + oauthToken;
        var war = await WebAuthenticationBroker.AuthenticateAsync(
                    WebAuthenticationOptions.None, new Uri(url), new Uri(_callbackUrl));
        switch (war.ResponseStatus)
        {
            case WebAuthenticationStatus.Success:
                return new TwitterRtPostResults
                {
                    Status = TwitterRtPostResults.EStatus.Success,
                    Dictionary = new TwitterRtDictionary(war.ResponseData)
                    // should contain oauth_token and oauth_verifier
                };</twitterrtpostresults>

What we are specifically looking for in the response are the parameters called “oauth_token” and “oauth_verifier”. No, these are not the tokens that allows us to tweet yet, but we are getting closer. We are ready for step 3.

Step 3: Converting the Request Token to an Access Token

Step 3 is where we actually get the token we wanted in the first place. We request this token by passing the two parameters we obtained from step 2. Notice that this time when we call PostData, we are passing a lot of parameters in the header, and one parameter in the request of the HTTP Post.

C#
// Step 3: Converting the request token to an access token
async Task<twitterrtpostresults> Step3(String oauthToken, String oauthVerifier)
{
    var header = new TwitterRtDictionary();
    header.Add("oauth_consumer_key", _consumerKey);
    header.Add("oauth_nonce", GenerateNonce());
    header.Add("oauth_signature_method", _signatureMethod);
    header.Add("oauth_timestamp", GenerateSinceEpoch());
    header.Add("oauth_token", oauthToken);
    header.Add("oauth_version", _oauthVersion);
    var request = new TwitterRtDictionary();
    request.Add("oauth_verifier", Uri.EscapeDataString(oauthVerifier));
    return await PostData(_accessTokenUrl, header, request);
    // should contain oauth_token, oauth_token_secret, user_id, and screen_name
}</twitterrtpostresults>

What we are specifically looking for in the response are the parameters called “oauth_token” and “oauth_token_secret”. Yes, these are the tokens that allows us to tweet!

We also get to finally find out the user_id and screen_name of our user. However, we don’t need to know these to tweet. We can hold on to them for the purposes of performing queries and other Twitter actions.

To some extent, that is all there is to signing in to Twitter.

Some Gory Details

Now for a brief description of the intricacies of PostData.

C#
async Task<TwitterRtPostResults> PostData(String url, 
     TwitterRtDictionary headerDictionary, TwitterRtDictionary requestDictionary = null)
{
    // See https://dev.twitter.com/docs/auth/creating-signature
    var combinedDictionaries = new TwitterRtDictionary(headerDictionary);
    combinedDictionaries.Add(requestDictionary);
    var signatureBase = "POST&" + Uri.EscapeDataString(url) + "&" + 
         Uri.EscapeDataString(combinedDictionaries.ToStringA());
    var keyMaterial = CryptographicBuffer.ConvertStringToBinary(_consumerSecret + 
         "&" + OauthTokenSecret, BinaryStringEncoding.Utf8);
    var algorithm = MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA1");
    var key = algorithm.CreateKey(keyMaterial);
    var dataToBeSigned = CryptographicBuffer.ConvertStringToBinary(
                          signatureBase, BinaryStringEncoding.Utf8);
    var signatureBuffer = CryptographicEngine.Sign(key, dataToBeSigned);
    var signature = CryptographicBuffer.EncodeToBase64String(signatureBuffer);
    var headers = "OAuth " + headerDictionary.ToStringQ() + 
          ", oauth_signature=\"" + Uri.EscapeDataString(signature) + "\"";
    return await PostData(url, headers, (requestDictionary == null) ? 
            String.Empty : requestDictionary.ToString());
}

Each time we send data to Twitter, we need to sign the content of the transmission (so no one can spoof us).

The data that we sign includes the text “POST”, plus the Twitter URL we are accessing, plus all the header and request data. All of these items need to be separated by an ampersand. The header and request data needs to be combined and then sorted. That is why we create a combined dictionary.

We sign the data with a signature that consists of our consumer secret data (provided to the constructor of TwitterRT) and the oauth_token_secret separated by an ampersand. However, in both steps 1 and 3, we do not yet have an oauth_token_secret. Remember that we get the oauth_token_secret as a return value from step 3. So until we have an oauth_token_secret, we need to sign all our requests with a signature that consists of our consumer secret data plus an ampersand (and nothing else). Yeah, I would think the ampersand should not be there if oath_token is missing, but I suppose that is the result of some tradition.

Once we have the signature, we have a bit more housekeeping to do before forwarding the post. Specifically, we need to send the header as comma-space separated parameters where all the values have to be within double-quotes. So why do we sign the header as a bunch of ampersand connected parameters with no double-quotes?  Tradition again, I suspect. We also need to add an additional parameter that contains the signature, called “oath_signature”. Of course, this signature needs to have special characters escaped.

In fact, there are many parameters that need to have special characters escaped, and many that do not. Either someone used a dart board to determine when to escape special characters and when not to or it is the result of some tradition. In any case, these are the fields that need to be escaped (all others should not be escaped):

  • status (when tweeting)
  • oauth_callback
  • oauth_verifier
  • all signed data
  • signature

Now you would think that the request parameters (like the header parameters) need to be comma-space separated parameters where all the values have to be within double-quotes too. Well, not quite. They need to be comma-space separated parameters where all the values are not within double-quotes. I suspect tradition is behind this one too.

There is another function called PostData that actually performs the HttpWebRequest. That function is pretty boring and self-explanatory.

Posting Tweets

The authoritative description of what needs to be done to tweet is very well described in Twitter’s very own Authorizing a request. Their document outlines all the parameters. It would be best if you kept both their document and this post open and side-by-side.

C#
// See https://dev.twitter.com/docs/auth/authorizing-request
public async Task<Boolean> UpdateStatus(String status) // a.k.a. tweet
{
    IsTweeting = true;
    Status = "Tweeting";
    var header = new TwitterRtDictionary();
    header.Add("oauth_consumer_key", _consumerKey);
    header.Add("oauth_nonce", GenerateNonce());
    header.Add("oauth_signature_method", _signatureMethod);
    header.Add("oauth_timestamp", GenerateSinceEpoch());
    header.Add("oauth_token", OauthToken);
    header.Add("oauth_version", _oauthVersion);
    var request = new TwitterRtDictionary();
    request.Add("status", Uri.EscapeDataString(status));
    var response = await PostData(_updateStatusUrl, header, request);
    IsTweeting = false;

    if (response.Status == TwitterRtPostResults.EStatus.Success)
    {
        Status = status;
        return true;
    }
    else
    {
        Status = response.Description;
        return false;
    }
}

The only parameter that needs special mention is the oauth_token. But of course we know that already came from step 3 above. Then all we need to do is load up the request with the status parameter, and poof, we are done. Of course, we again rely on PostData to do all the heavy lifting here.

I hope this has been helpful on providing some insight into the whole OAUTH process. I think OAUTH is a great concept, very powerful in its implementation, but full of very annoying “traditions”.

Image 2

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)