Twitter Development: The OAuth Workflow

Normal
0

false
false
false

EN-US
X-NONE
X-NONE

MicrosoftInternetExplorer4

This article is excerpted from Chapter 6: Basic Authentication and OAuth of the Wrox book, Professional Twitter Development: With Examples in .NET 3.5, by Daniel Crenna, and is reused by permission of the publisher. This may not be reused without publisher permission.

 
OAuth Workflow
 
The OAuth workflow is a series of automated steps that lead a user to opt-in to give your application privileges to a publisher site, and then convert that explicit authorization into credentials you can pass to the publisher’s API to access protected resources. Figure 6-2, from the OAuth specification available at http://oauth.net, illustrates the client and server processes that occur from the time your application starts, and a user completes the authorization process, to what occurs afterward.
 
Figure 6-2       
 
Although the OAuth specification encompasses publisher tasks as well, you are concerned only with how to participate in the process to help your user use your application in a safe and secure way. The details of each of the four major steps you’ll participate in as a consumer (retrieving a request token, directing your user to the authorization site, exchanging an access token, and finally accessing a protected resource) are covered in detail here.
 
 

OAuth Test Servers
 
Because OAuth is a standardized protocol, you are not limited to Twitter’s servers when testing your OAuth implementation. Here are a few OAuth test servers you can use. If you need to find more servers, a quick Google search should provide some current resources.
(This tool requires a MySpace developer account.)
Retrieving an Unauthorized Request Token
The first step in the OAuth workflow is for your code to make an OAuth request to the publisher’s request token URL. This request starts the authorization process and lets a publisher know you are trying to secure a connection. The request token is unauthorized because it is too early in the process to obtain a user’s authorization to use your application. After this authorization is granted, however, the token you retrieve becomes an authorized token you can exchange for accessing the publisher’s resources. You can build a set of reusable methods to structure this request token call and employ the methods you’ve already created to build a successful OAuth request. Here is what the code for this utility method might look like.
using System;
using System.Collections.Specialized;
using System.Net;
using System.Text;
using System.Web;
using Wrox.Twitter.NUrl;
            
partial class OAuth
{
    public static string GetRequestToken(string url,
                                         string consumerKey,
                                         string consumerSecret)
    {
        // get any parameters in the request body
        // to use in the OAuth signature
        var uri = new Uri(url);
        var parameters = HttpUtility.ParseQueryString(uri.Query);
            
        // collect the required OAuth signature data to make a request
        var oauthParameters = GetOAuthParameters(parameters,
                                                url,
                                                “GET”,
                                                consumerKey,
                                                consumerSecret);
            
        // create a new request with OAuth authorization set
        var request = BuildOAuthWebRequest(oauthParameters,
                                           url,
                                           null,
                                           null);
            
        // send the request to get back a request token
        var token = request.Get();
        return token;
    }
}
var parameters = HttpUtility.ParseQueryString(uri.Query);.
 
The example demonstrates that an important part of signature generation is including any other parameters defined in the URI in the signature base.
 
Useful Functions for Sending OAuth Requests
You can add a quick feature upgrade to NUrl, the request library you built in Chapter 2, to allow executing requests directly from the HttpWebRequest object rather than a URL, and to help make it easy to send OAuth calls after they are properly created.
public static string Get(this HttpWebRequest request)
{
    return ExecuteGet(request);
}
 
You can also use the handy ParseQueryString method provided by HttpUtility to quickly obtain a collection of request parameters from an existing Uri, which you can use to prepare OAuth signatures combining both regular request parameters with OAuth credentials.
var uri = new Uri(url);
var parameters = HttpUtility.ParseQueryString(uri.Query);.
 
After you create a collection of OAuth parameters including the new signature, you can build a web request that includes the authorization header, and make the request to retrieve the request token. The following code rounds out this example with the supporting methods used.
using System;
using System.Collections.Specialized;
using System.Net;
using System.Text;
using System.Web;
using Wrox.Twitter.NUrl;
            
partial class OAuth
{
    private static HttpWebRequest BuildOAuthWebRequest(
        NameValueCollection oauthParameters,
        string url,
        string httpMethod,
        string realm)
    {
        var header = new StringBuilder();
        header.Append(“OAuth “);
            
        if (!string.IsNullOrEmpty(realm))
        {
            // add realm info if provided
            header.Append(“realm=”” + realm + “” “);
        }
            
        for (var i = 0; i < oauthParameters.Count; i++)
        {
            var key = oauthParameters.GetKey(i);
            var pair = key + “=”” + oauthParameters[key] + “””;
            
            header.Append(pair);
            if (i < oauthParameters.Count – 1)
            {
                header.Append(“,”);
            }
        }
            
        // create a new request and set the OAuth header
        var request = (HttpWebRequest) WebRequest.Create(url);
        request.Headers[“Authorization”] = header.ToString();
            
        Console.WriteLine(header.ToString());
        return request;
    }
            
    private static NameValueCollection GetOAuthParameters(
        NameValueCollection requestParameters,
        string url,
        string httpMethod,
        string consumerKey,
        string consumerSecret)
    {
        if (requestParameters == null)
        {
            requestParameters = new NameValueCollection();
        }
            
        var timestamp = CreateTimestamp().ToString();
        var nonce = CreateNonce();
            
        // create oauth requestParameters
        var oauthParameters = new NameValueCollection
                              {
                                  {“oauth_timestamp”, timestamp},
                                  {“oauth_nonce”, nonce},
                                  {“oauth_version”, “1.0”},
                                  {“oauth_signature_method”, “HMAC-SHA1”},
                                  {“oauth_consumer_key”, consumerKey}
                              };
            
        // fold oauth into any existing request request parameters
        foreach (var oauthKey in oauthParameters.AllKeys)
        {
            requestParameters.Add(oauthKey, oauthParameters[oauthKey]);
        }
            
        // prepare a signature base
        url = NormalizeUrl(url);
        var normalizedParameters =
            NormalizeRequestParameters(requestParameters);
        var signatureBase = ConcatenateRequestElements(httpMethod,
                                                       url,
                                                       normalizedParameters);
             
        // obtain a signature and add it to header requestParameters
        var signature = CreateSignature(signatureBase, consumerSecret, null);
        oauthParameters.Add(“oauth_signature”, signature);
            
        return oauthParameters;
   }
}
 
When a request token is returned from the server, it comes in the form of a set of name value pairs, specifically oauth_token and oauth_token_secret. You can parse out these values and use them in the later steps of the workflow. Using this utility code, retrieving the request token and its secret is easy.
// Twitter’s URL for obtaining a request token
const string url = “http://twitter.com/oauth/request_token”;
            
// You get these from your Twitter application’s setting page
const string key = “key”;
const string secret = “secret”;
            
// make an OAuth call to get a request token using your key and secret
var response = OAuth.GetRequestToken(url, key, secret);
            
// parse the response values
var collection = HttpUtility.ParseQueryString(response);
            
// create an anonymous type containing the token parameters
var token = new {Token = collection[0], TokenSecret = collection[1]};
 
Redirecting the User to the Provider Authorization Site
 
Retrieving the request token is the easiest step in the OAuth workflow; it does not require user interaction. However, the success of OAuth hinges on a user’s explicit authorization for your application to access a publisher’s services on behalf of the user, but without revealing the user’s credentials. To accomplish this, your code must send the user to the publisher itself, where they will enter credentials and accept or deny access privileges to your application. How you perform this step is largely based on your application’s architecture; a desktop or mobile application will need to open a new browser instance, whereas an ASP.NET web application could simply redirect the user. Your publisher will provide an authorization URL for this purpose. You need to also provide the request token you obtained in the last step as a query parameter in the outgoing authorization URL; this lets the publisher know that you are engaging the OAuth challenge and response, and what application is attempting to access Twitter on your user’s behalf. You will learn how to authorize multiple application types later in the Walkthroughs section in this chapter, but for nowthis example code demonstrates how a .NET desktop application could obtain user authorization.
 
// This is the URL Twitter provides for user authorization;
// you must pass the OAuth request token to the URL
var authorizeUrl = “http://twitter.com/oauth/authorize?oauth_token=”;
            
// You would use the request token acquired in the first workflow step
var url = String.Concat(authorizeUrl, Uri.EscapeDataString(“oauth_token));
            
// This will start the default browser with the constructed URL
Process.Start(url);
 
The result of the call to create a new browser instance is shown in Figure 6-3, showing your custom application as you configured it on Twitter, with options for the user to accept or deny application access.
 
Figure 6-3
 
One deceptive aspect of this process is that the authorization occurs out-of-band; there is nothing left for your application to do. If you are building a desktop application, you need to wait around for the user to complete the authorization process before continuing with an OAuth workflow; you will have no way of confirming when the user is complete, and the user will need to return to your application without assistance. There are user experience concerns with this that you will consider in Authenticating a Desktop, Console, or Mobile Application later in this chapter. If you are building a web application, Twitter will redirect the user for you to a callback URL that you provide in the configuration process.
 
Exchanging a Request Token for an Authorized Access Token
 
At this stage in the OAuth workflow, you retrieved a request token, sent your user to the publisher’s site, and are waiting to find out if the user accepted or denied your application. Your publisher will provide an access token URL, which you can exchange with the request token you obtained in the first step in the workflow. If the user accepted your request, you will receive an access token, which you can persist if desired, and use repeatedly to access authorized methods on the publisher API. If the user denied your request, the exchange will fail. You can write another utility method to ease the process of exchanging the request token for an access token, using the following code.
using System;
using System.Collections.Specialized;
using System.Net;
using System.Text;
using System.Web;
using Wrox.Twitter.NUrl;
            
partial class OAuth
{
    public static string GetAccessToken(string url,
                                            string consumerKey,
                                            string consumerSecret,
                                            string requestToken,
                                            string requestTokenSecret)
    {
        // get any parameters in the request body
        // to use in the OAuth signature
        var uri = new Uri(url);
        var parameters = HttpUtility.ParseQueryString(uri.Query);
            
        // collect the required OAuth signature data to make a request
        var oauthParameters = GetOAuthParameters(parameters,
                                                 url,
                                                 “GET”,
                                                 consumerKey,
                                                 consumerSecret,
                                                 requestToken,
                                                 requestTokenSecret);
            
        // create a new request with OAuth authorization set
        var request = BuildOAuthWebRequest(oauthParameters, url, null);
            
        // send the request to get back a request token
        var token = request.Get();
        return token;
    }
}
 
Looking closer, you’ll see that the code to exchange for the access token is almost identical to the code to fetch an unauthorized request token, with the exception of passing the request token to the signature generation utility. To make this method work with a request token, you need to modify the existing helper methods to know to make use of the request token when it is required, but default to existing behavior when it is missing. You can accomplish this with the following modifications.
 
using System;
using System.Collections.Specialized;
using System.Net;
using System.Text;
using System.Web;
using Wrox.Twitter.NUrl;
            
partial class OAuth
{
    private static NameValueCollection GetOAuthParameters(
        NameValueCollection requestParameters,
        string url,
        string httpMethod,
        string consumerKey,
        string consumerSecret,
        string requestToken,
        string requestTokenSecret)
    {
        if (requestParameters == null)
        {
            requestParameters = new NameValueCollection();
        }
            
        var timestamp = CreateTimestamp().ToString();
        var nonce = CreateNonce();
            
        // create oauth requestParameters
        var oauthParameters = new NameValueCollection
                             {
                                  {“oauth_timestamp”, timestamp},
                                  {“oauth_nonce”, nonce},
                                  {“oauth_version”, “1.0”},
                                  {“oauth_signature_method”, “HMAC-SHA1”},
                                  {“oauth_consumer_key”, consumerKey}
                              };
            
        // add the request token if found
        if(!String.IsNullOrEmpty(requestToken))
        {
                oauthParameters.Add(“oauth_token”, requestToken);
        }
            
        // fold oauth into any existing request request parameters
        foreach (var oauthKey in oauthParameters.AllKeys)
        {
            requestParameters.Add(oauthKey, oauthParameters[oauthKey]);
        }
            
        // prepare a signature base
        url = NormalizeUrl(url);
        var normalizedParameters =
            NormalizeRequestParameters(requestParameters);
        var signatureBase = ConcatenateRequestElements(httpMethod,
                                                       url,
                                                       normalizedParameters);
            
        // obtain a signature and add it to header requestParameters
       var signature = CreateSignature(signatureBase,
                                        consumerSecret,
                                        requestTokenSecret);
        oauthParameters.Add(“oauth_signature”, signature);
            
        return oauthParameters;
    }
            
    private static NameValueCollection GetOAuthParameters(
        NameValueCollection requestParameters,
        string url,
        string httpMethod,
        string consumerKey,
        string consumerSecret)
    {
        // the original request is now a method overload
        return GetOAuthParameters(requestParameters,
                                 url,
                                 httpMethod,
                                 consumerKey,
                                 consumerSecret,
                                 null,
                                 null);
    }
}
 
Obtaining an access token with your new utility class is as simple as providing the consumer key and secret, along with the request token previously acquired, demonstrated with this code.
 
// at this point you should have sent the user to the authorization page,
// using the request token you retrieved in the first step
var response = OAuth.GetAccessToken(url, key, secret, token, tokenSecret);
            
// parse the response values
var collection = HttpUtility.ParseQueryString(response);
            
// create an anonymous type containing the access token parameters
var accessToken = new {Token = collection[0], TokenSecret = collection[1]};
    
Accessing a Protected Resource with an Access Token
 
You’re ready to start using the access token, which provides the publisher with both confirmation of a user’s authorization to use your application and which application the authorization is for.
 
Saving Access Tokens
 
It’s important to note that although the publisher knows which user the access token and secret apply to, it is not obvious from code. If you intend to save the token for reuse, you should pair it with additional user profile information so you don’t have to guess who the token belongs to at runtime. If you elect not to save token data, you can repeat the OAuth workflow process each time, but doing so could degrade the user experience.
To access protected resources with an OAuth token, you can use the following code.
 
using System;
using System.Collections.Specialized;
using System.Net;
using System.Text;
using System.Web;
using Wrox.Twitter.NUrl;
            
partial class OAuth
{
    public static string GetProtectedResource(string url,
                                              string httpMethod,
                                              string consumerKey,
                                              string consumerSecret,
                                              string accesssToken,
                                              string accessTokenSecret)
    {
        // get any parameters in the request body
        // to use in the OAuth signature
        var uri = new Uri(url);
        var parameters = HttpUtility.ParseQueryString(uri.Query);
            
        // keep a copy of the non-OAuth parameters
        var queryParameters = new NameValueCollection(parameters);
            
        // collect the required OAuth signature data to make a request
        var oauthParameters = GetOAuthParameters(parameters,
                                                 url,
                                                 httpMethod,
                                                 consumerKey,
                                                 consumerSecret,
                                                 accesssToken,
                                                 accessTokenSecret);
            
        // if posting, rebuild the URI without the query
        if (httpMethod.ToUpper().Equals(“POST”))
        {
            url = String.Concat(uri.Scheme,
                                “://”,
                                uri.Authority,
                                uri.AbsolutePath);
        }
             
            
        // create a new request with OAuth authorization set
        var request = BuildOAuthWebRequest(oauthParameters,
                                           url,
                                           null);
        // send the request to get back a request token
        string response = null;
        switch (httpMethod.ToUpper())
        {
            case “GET”:
                // using NUrl to send an HTTP GET
                response = request.Get();
                break;
            case “POST”:
                request.Method = “POST”;
                request.ContentType = “application/x-www-form-urlencoded”;
            
                // collect non-OAuth parameters for the post body
                var sb = new StringBuilder();
                for (var i = 0;
                     i < queryParameters.AllKeys.Length;
                     i++)
                {
                    var key = queryParameters.AllKeys[i];
                    sb.AppendFormat(“{0}={1}”,
                                   Uri.EscapeDataString(key),
                                    Uri.EscapeDataString(
                                        queryParameters[key]));
            
                    if (i < queryParameters.Count – 1)
                    {
                        sb.Append(“&”);
                    }
                }
            
                // write only the query parameters in the POST body
                var body = sb.ToString();
                var content = Encoding.ASCII.GetBytes(body);
                response = request.Post(content);
                break;
        }
            
        Console.WriteLine(request.RequestUri.ToString());
        return response;
    }
}
 
Because your queries will typically include more parameters than the OAuth authentication info alone, you will need to provide them for signature signing, but also write them explicitly in an HTTP POST method. With this method in place, accessing protected resources from a desktop application, starting from the beginning of an OAuth workflow, could look similar to the following code example:
 
// This is the URL to retrieve a request token
const string requestUrl = “http://twitter.com/oauth/request_token”;
            
// This is the URL to exchange the request token for an access token
const string accessUrl = “http://twitter.com/oauth/access_token”;
            
// This is the URL to access a protected resource; in this case,
// the authorized user’s timeline
const string userTimeline = “http://twitter.com/statuses/user_timeline.xml”;
            
// This is your application’s consumer key
const string key = “key”;
            
// This is your application’s consumer secret
const string secret = “secret”;
            
// This is the URL to send a user for authorization
const string authorizeUrl = “http://twitter.com/oauth/authorize?oauth_token=”;
            
// Retrieve and parse the request token
var response = OAuth.GetRequestToken(requestUrl, key, secret);
var collection = HttpUtility.ParseQueryString(response);
var requestToken = new { Token = collection[0], TokenSecret = collection[1] };
            
// At this point, your application must wait for the user to return
var url = String.Concat(authorizeUrl,
                        Uri.EscapeDataString(requestToken.Token));
Process.Start(url);
            
// Exchange the request token for the access token after user approval
response = OAuth.GetAccessToken(accessUrl,
                                key,
                                secret,
                                requestToken.Token,
                                requestToken.TokenSecret);
collection = HttpUtility.ParseQueryString(response);
var accessToken = new { Token = collection[0], TokenSecret = collection[1] };
            
// Get the user timeline using OAuth credentials
response = OAuth.GetProtectedResource(userTimeline,
                                      “GET”,
                                      key,
                                      secret,
                                      accessToken.Token,
                                      accessToken.TokenSecret);
 
Now you are ready to build Twitter applications that respect user credentials and instill trust in your user base. OAuth, although strict and comprehensive, is a valuable addition to your web developer skill set in user management, and an important part of your Twitter development portfolio. In the next section you’ll learn how to apply OAuth to Twitter applications on the web and on the desktop.
 
To be continued… See article: "Using OAuth to authenticate against the Twitter API: Walkthroughs"

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *