Accessing the Twitter API with Mobile Services

If you have been reading at all about Azure Mobile Services you know that the system supports authentication through 4 different third party providers: Facebook, Twitter, Google Plus, and Windows Live (or whatever they are calling it these days).  The setup for your Mobile Service must precede any code that you write.  This process involves gathering consumer keys and secret and making your mobile service aware of them.  The folks at Microsoft have some excellent documentation around this: http://www.windowsazure.com/en-us/develop/mobile/tutorials/get-started-with-users-dotnet/

By using one of these methods you effectively off load the handling of authentication to the appropriate site.  This is becoming a very common approach to authentication due to the proliferation of these services.  Here is a quick example of how to do do this authentication in Azure Mobile Services:

        private async void btnAuthorize_OnClick(object sender, RoutedEventArgs ev)
        {
            var client = new MobileServiceClient("Your Mobile Service Url", AppKey);
            var userData = await client.LoginAsync(Provider);
        }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

This is very simple and straightforward.  Running this code should cause the appropriate login form to come in.  The form and associated window should disappear if authentication is successful.

If we look at userData we will see two values within: UserId and MobileServiceAuthenticationToken.  Depending on what you intend to use the authentication for you may wish to save one or both values:

  • If you intend to configure some or all actions on a Mobile Service endpoint (table) to require user authentication you will NEED to know the MobileServiceAuthenticationToken when making those requests along with the UserId
  • If you intend (as I will show to look a user up to get additional information, I recommend the UserId value)

For the purposes of this exercise we will be storing just the UserId value.  The general process beyond this point is, when the app starts up, attempt to get this UserId value and look for it in an Azure Mobile Service endpoint (table).  If found, download additional information that will be useful for access the related API, for example OAuth Access token information.

For whatever reason, the existing Login method does NOT return to your application the OAuth information these services use.  However, it is available to you with a special call within your REST endpoint.  Here is an example of the insert trigger which I call after the user has successfully logged in to a service, in my case Twitter:

function insert(item, user, request) {

    var identity = user.getIdentities();
    var userId = identity.twitter.userId;
    var accessToken = identity.twitter.accessToken;
    var accessTokenSecret = identity.twitter.accessTokenSecret;
    
    var identityTable = tables.getTable("identity");
    var insertItem = {
      userId: userId,
      accessToken: accessToken,
      accessSecretToken: accessTokenSecret  
    };

    identityTable.insert(insertItem, {
        success: function(result) {
          request.respond(200, insertItem);
        },
        error: function(code) {
            console.log(code);
            console.log("Something went wrong");
            request.respond(500);
        }
    });
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

The key call here is getIdentities() on the user object. In this way you can get additional information for a particular user.  Remember, however, that you will get null if the user is not authenticated.  To be certain of this, I recommend the table require user authentication for the given action.

My recommendation here is to call this trigger immediately after the user is verified via Login, as all of the information needed will be available at that point.  Once you insert the user with the access token and secret, you need only look up the user to get this information, hence why it was mentioned that the UserId should be stored and used a lookup key.

In addition, the script above sends the new identity object as part of the response to the caller.  This gives the caller immediate access to the Access Token and Access secret.

Getting a List of User Status Updates from Twitter

Disclaimer: the process I am going to show will rely on RestSharp (http://www.restsharp.org) to make REST calls to the Twitter API.  Because of this approach I will be showing how to actually build an authorized request.  This process is very tedious and error prone, I recommend using an SDK instead when doing this sort of thing in production.

Now that you have the Access Token and Secret you can make calls to Twitter.  Making calls to Twitter, however, is not easy and requires a lot of setup with respect to the request being made.  Full details are available here: Authorizing a request

At the center of authorizing a Twitter request is the Authorization header value.  The value of this header is comprised of encoded values from all parameters given to the request.  Here is a list:

Consumer Key  this is the value given to you through the Twitter developer console to identify you application.  This value will remain constant through the life of your application. Parameter name: oauth_consumer_key

Nonce – This one confused me for the longest time.  All it is really is a random string designed to identify the request to Twitter.  Generate this once per request.  Here is the code I used to generate mine:

        private string GenerateNonce()
        {
            return Guid.NewGuid().ToString().Replace("-", string.Empty);
        }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Parameter Name: oauth_nonce

Signature – this is probably the most annoying one.  It is Base64 encoded string representing all other parameter values given to the request.  I will describe this process later, but this is how Twitter explains it: https://dev.twitter.com/docs/auth/creating-signature

Signature Method – this is a constant value of “HMAC-SHA1”. Parameter name: oauth_signature_method

Timestamp – this is the number of seconds since the UNIX Epoch (1/1/1970).  This value is critical and must be calculated correctly. Always check the date and time on your Windows Phone emulator (mine was way off) if you start getting timestamp errors.  Here is my code:

        private int UnixTimestamp
        {
            get { return (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; }
        }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Parameter name: oauth_timestamp

Token – this is the access token that you were given by Azure Mobile Services.  This token represents a users acceptance that your application is permitted to access their data. Parameter name: oauth_token

Version – this is a constant value of “1.0”Parameter name: oauth_version

Putting it together

To build this string you need to create a string of the format: “OAuth ”.  The actual step by step instructions can be viewed at the link I provided earlier.  However, I have always found code to be easier to understand, so here is my code generating this string:

        private string CreateAuthorizationHeaderString(string signature, string nonce, string ts)
        {
            var authString = new StringBuilder();
            authString.Append("OAuth ");
            var authParams = new Dictionary<string, string>
                    {
                        {"oauth_consumer_key", _consumerKey},
                        {"oauth_nonce", nonce},
                        {"oauth_signature", signature},
                        {"oauth_signature_method", SigMethod},
                        {"oauth_timestamp", ts
                        {"oauth_token", _accessToken},
                        {"oauth_version", Version}
                    };

            var isFirst = true;
            foreach (var kv in authParams)
            {
                if (!isFirst)
                    authString.Append(", ");

                authString.AppendFormat("{0}=\"{1}\"", WebUtility.UrlEncode(kv.Key),
                                                       WebUtility.UrlEncode(kv.Value));
                isFirst = false;
            }

            return authString.ToString();
        }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Aside from the value of signature all of the values are accounted for and populated.  The result of this method gets added into the request as a header (as the name implies).  Here is the code for that:

AddHeader("Authorization", CreateAuthorizationHeaderString(signature, nonce, timestamp));

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

The first step in creating the signature is gathering all of the parameters that will be needed.  They include:

  • A dictionary containing all of the parameter values from above, minus the signature key value pair.  Note that it should also include ANY parameters you are passing in the query string as well
  • The string representation of the method to be used for the request: ex: “GET” or “POST”
  • The full URL that will be accessed.  Do NOT include any query string information

Note: this process makes heavy use of URL encoding.  You can access these methods using the System.Net.WebUtility helper class.

The first part of the parameter string is a combination of an uppercase string representing the HTTP method being used and the percent encoded (Url encoded) request Url (with query string parameters) separated by an ‘&’.  Like this:

var sb = new StringBuilder();
sb.AppendFormat("{0}&", method.ToUpper(), WebUtility.UrlEncode(baseUrl));

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Next you will want to concatenate the authorization parameters. My recommendation is to use a LINQ query to rebuild the dictionary so that it contains ONLY percent encoded (Url encoded) values and is appropriately sorted.  Here is an example of what I did:

parameters = parameters.Select(kv => new
{
    Key = WebUtility.UrlEncode(kv.Key),
    Value = WebUtility.UrlEncode(kv.Value)
}).OrderBy(ao => ao.Key).ThenBy(ao => ao.Value)
                       .ToDictionary(ao => ao.Key, ao => ao.Value);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Next, you will want to look through this dictionary and build it up much like a query string looks with and equal (‘=’) between the keys and values and am ampersand (&) between the actual pairs.  Here is my loop:

var isFirst = true;
foreach (var param in parameters)
{
    if (!isFirst)
        paramString.Append("&");

    paramString.AppendFormat("{0}={1}", param.Key, param.Value);
    isFirst = false;
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Always, remember that when doing string concatenation to utilize the System.Text.StringBuilder class to carry out the operation.  That is what I am using here with paramString.

Next, you take the entire parameter string and percent encode (Url encode) it.  So like this:

WebUtility.UrlEncode(paramString.ToString())

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Next, we have to create a signing key before we can use SHA1 to create our hash.  This is done by encoding the Consumer Secret and Access Token Secret together into a predefined string format like this:

var signingKey = new StringBuilder();
signingKey.AppendFormat("{0}", WebUtility.UrlEncode(_consumerSecret),
                        WebUtility.UrlEncode(_accessTokenSecret));

var hasher = new HMACSHA1(Encoding.UTF8.GetBytes(signingKey.ToString()));

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Doing this effectively creates your signing key which  you can use to initialize the SHA1 hash algorithm.  The next step is hash the entire parameter string that you have created thus far and then return the Base64 representation of it, this represents the oauth_signature.

The entire code for making this request is located here: https://dl.dropboxusercontent.com/u/16266819/TwitterRequest.cs

Making the Request

So at the start of this I talked about how we can use Mobile Services to authenticate ourselves and through a call on the user object inside the REST endpoint we can get all of the information needed to make authorized requests.  We then walked through the steps to creating an authorized Twitter request, so now lets make the request.

For the purposes of this I have written a couple awaitable methods so that we can take advantage of the new asynchronous programming model available in .NET 4.5.  Center to his is the Execute method within the TwitterRequest class:

public Task<string> Execute(RestClient client, string resource, Method method)
{
    var tcs = new TaskCompletionSource<string>();
    client.ExecuteAsync(this, response =>
        {
            if (response.ResponseStatus == ResponseStatus.Completed)
                tcs.SetResult(response.Content);
            else
                tcs.SetException(response.ErrorException);
        });

    return tcs.Task;
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Without getting too much into what is going on here, the TaskCompletionSource informs .NET that any dependencies on the return value of this method should be held until the value is ready.  We notify it is ready by calling SetResult, conversely we can inform the system of an error through SetException.  The return value of this method the Task which will hold the response string (we are retrieving JSON from this request).  I can then make the following call to get the last 20 status for the authorized user:

public async Task<IList> GetStatusUpdates()
{
    var restClient = new RestClient("https://api.twitter.com/1.1/");
    var request = new TwitterRequest("https://api.twitter.com/1.1/statuses/user_timeline.json",
                                     "statuses/user_timeline.json", Method.GET, ConsumerKey, ConsumerSecret,
                                     _accessToken, _accessTokenSecret);

    string result = await request.Execute(restClient, "user_timeline.json", Method.GET);
    var statusArray = JArray.Parse(result).AsJEnumerable();

    return statusArray.Select(jo => new StatusUpdate
    {
        Status = jo["text"].ToString(),
        Source = jo["source"].ToString(),
        UserLocation = jo["user"]["location"].ToString()
    }).ToList();
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Within this method we are very explicit about the importance of the result variable in finishing the method.  .NET will see this and ensure that code dependant on result is not executed until SetResult is called.  When it is, the remainder of this code should be self explanatory.  The actual call to this client looks like this:

private async void btnGetTweets_OnClick(object sender, RoutedEventArgs ev)
{
    var client = new TwitterClient(oauth_consumer_key, oauth_consumer_secret);
    client.SetAuthorization(_mobileServiceUser.AccessToken,
        _mobileServiceUser.AccessTokenSecret);

    var results = await client.GetStatusUpdates();
    lstTweets.ItemsSource = results;
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Simple, although I am still working to clean up the integration points between the Client and the Request, but this is workable for now.

I hope this article has helped you understand how using Azure Mobile Services can be valuable when interfacing with APIs like Facebook or Twitter.  I often find that the most difficult part of this process is the authentication and being able to get the Access Token and Access Token Secret, so to be able to use Azure Mobile Service to get in literally four lines of code is quite nice

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s