Udostępnij za pośrednictwem


Extending HttpClient with OAuth to Access Twitter

Many popular Web APIs such as the twitter API use some form of OAuth for authentication. HttpClient does not have baked in support for OAuth but using the HttpClient extensibility model you can add OAuth as part of the HttpMessageHandler pipeline.

The HttpMessageHandler pipeline is the main extensibility point for the HTTP object model underlying both HttpClient and ASP.NET Web API (they use the exact same model). The pipeline allows up to insert message handlers that can inspect, modify, and process HTTP requests and responses as they pass by. The following diagram shows where HttpMessageHandlers sit in the message path on both client (HttpClient) and server side (ASP.NET Web API). The work like “Russian Dolls” in that each handler passes the request to an inner handler until it hits the network or is short-circuited":

HttpMessageHandlers

Note that there is absolutely no requirement that you have to use the HttpClient with ASP.NET Web API – it is just to show that the model is symmetric on client and server side.

Our OAuth handler is very simple – it uses the a sample from OAuth.Net provided by Eran Sandler to do the actual OAuth signing.

Please see List of ASP.NET Web API and HttpClient Samples for the complete sample solution.

Getting a Twitter API Key

The first step is to sign in at the twitter developer site and create an app. That will give you necessary information for performing the OAuth authentication:

  • Consumer Key and Consumer Secret: identifies your application
  • Access Token and Access Token Secret: identifies the account your application is acting on behalf of

Once you have these values then you can continue with the sample.

Creating a HttpMessageHandler

First we create the OAuth HttpMessageHandler like this. The OAuthBase class is the OAuth signature generator from Eran Sandler mentioned above. Every time a request is submitted it hits the SendAsync method where we get the information from the request and update it with an appropriate OAuth authentication header before sending it on its way to the next handler.

    1: /// <summary>
    2: /// Basic DelegatingHandler that creates an OAuth authorization header based on the OAuthBase
    3: /// class downloaded from https://oauth.net
    4: /// </summary>
    5: public class OAuthMessageHandler : DelegatingHandler
    6: {
    7:     // Obtain these values by creating a Twitter app at https://dev.twitter.com/
    8:     private static string _consumerKey = "Enter your consumer key";
    9:     private static string _consumerSecret = "Enter your consumer secret";
   10:     private static string _token = "Enter your token";
   11:     private static string _tokenSecret = "Enter your token secret";
   12:  
   13:     private OAuthBase _oAuthBase = new OAuthBase();
   14:  
   15:     public OAuthMessageHandler(HttpMessageHandler innerHandler)
   16:         : base(innerHandler)
   17:     {
   18:     }
   19:  
   20:     protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   21:     {
   22:         // Compute OAuth header 
   23:         string normalizedUri;
   24:         string normalizedParameters;
   25:         string authHeader;
   26:  
   27:         string signature = _oAuthBase.GenerateSignature(
   28:             request.RequestUri,
   29:             _consumerKey,
   30:             _consumerSecret,
   31:             _token,
   32:             _tokenSecret,
   33:             request.Method.Method,
   34:             _oAuthBase.GenerateTimeStamp(),
   35:             _oAuthBase.GenerateNonce(),
   36:             out normalizedUri,
   37:             out normalizedParameters,
   38:             out authHeader);
   39:  
   40:         request.Headers.Authorization = new AuthenticationHeaderValue("OAuth", authHeader);
   41:         return base.SendAsync(request, cancellationToken);
   42:     }
   43: }

The way this is wired up to an HttpClient is by using the HttpClient constructor that takes a HttpMessagHandler:

    1: // Create client and insert an OAuth message handler in the message path that 
    2: // inserts an OAuth authentication header in the request
    3: HttpClient client = new HttpClient(new OAuthMessageHandler(new HttpClientHandler()));

The HttpClientHandler is the default “network” handler provided by HttpClient that actually sends the request and received the response from the network.

Creating a Twitter Client

The only thing left is now to create the program submitting a request to twitter and handling the response. We use JsonValue to parse the data returned by twitter when accessing the latest entries posted by Scott Guthrie. When you submit the request, the request will hit the OAuth message handler and then make its way to the network.

    1: /// <summary>
    2: /// Sample illustrating how to write a simple twitter client using HttpClient. The sample uses a 
    3: /// HttpMessageHandler to insert the appropriate OAuth authentication information into the outgoing
    4: /// HttpRequestMessage. The result from twitter is read using JsonValue.
    5: /// </summary>
    6: class Program
    7: {
    8:     static string _address = "https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=true&screen_name=scottgu&count=5";
    9:  
   10:     static void Main(string[] args)
   11:     {
   12:         // Create client and insert an OAuth message handler in the message path that 
   13:         // inserts an OAuth authentication header in the request
   14:         HttpClient client = new HttpClient(new OAuthMessageHandler(new HttpClientHandler()));
   15:  
   16:         // Send asynchronous request to twitter
   17:         client.GetAsync(_address).ContinueWith(
   18:             (requestTask) =>
   19:             {
   20:                 // Get HTTP response from completed task.
   21:                 HttpResponseMessage response = requestTask.Result;
   22:  
   23:                 // Check that response was successful or throw exception
   24:                 response.EnsureSuccessStatusCode();
   25:  
   26:                 // Read response asynchronously as JsonValue and write out tweet texts
   27:                 response.Content.ReadAsAsync<JsonArray>().ContinueWith(
   28:                     (readTask) =>
   29:                     {
   30:                         JsonArray statuses = readTask.Result;
   31:                         Console.WriteLine("\nLast 5 statuses from ScottGu's twitter account:\n");
   32:                         foreach (var status in statuses)
   33:                         {
   34:                             Console.WriteLine(status["text"] + "\n");
   35:                         }
   36:                     });
   37:             });
   38:  
   39:         Console.WriteLine("Hit ENTER to exit...");
   40:         Console.ReadLine();
   41:     }
   42: }

The output when running this sample should be 5 tweets written to the console.

Have fun!

Henrik

del.icio.us Tags: asp.net,webapi,mvc,web,rest,httpclient

Comments

  • Anonymous
    February 16, 2012
    Nice Post!! I for one would like to see samples/support for going through the entire oAuth workflow with WebAPI and HttpClient. Getting the token, handling expired tokens, maybe oAuth2 support also?

  • Anonymous
    February 16, 2012
    That is a good suggestion - it is on the list but we are still working on it.

  • Anonymous
    February 16, 2012
    Great. But what about X509 certificate?

  • Anonymous
    February 18, 2012
    You can set up certificates on the WebRequestHandler and then pass that handler to HttpClient in the ctor like this new HttpClient(MyWebRequesthandler)

  • Anonymous
    February 21, 2012
    The comment has been removed

  • Anonymous
    February 23, 2012
    Henrik, I tried to use the HttpClient with AsyncCTP features (await) and it worked. But I am not sure I got it right in terms of implementation. Can you have a look for me? github.com/.../Program.cs

  • Anonymous
    February 25, 2012
    I had to generate the AuthHeader as follows:        private static string GenerateAuthHeader(string consumerKey, string token, string timeStamp, string nonce, string signature, string signatureMethod)        {            string authHeader;            authHeader = string.Format(                "oauth_consumer_key="{0}", oauth_nonce="{1}", oauth_signature="{2}", oauth_signature_method="{3}", oauth_timestamp="{4}", oauth_version="{5}"",                consumerKey,                nonce,                Uri.EscapeDataString(signature),                signatureMethod,                timeStamp,                OAuthVersion);            if (string.IsNullOrEmpty(token))            {                return authHeader;            }            return authHeader + string.Format(", oauth_token="{0}"", token);        } after that was done, the sample worked great, thank you!

  • Anonymous
    April 04, 2012
    Hope you don't mind, I copied your sample code to GitHub github.com/.../TwitterHttpClientSample

  • Anonymous
    May 14, 2012
    Nice post. Thanks for sharing. I have a question: I wrote a client with twitter and linkedIn and after getting the access code, server will return a verification code. I want to get this code automatically. Do you think it's possible? Regards, Steven Nguyen

  • Anonymous
    November 27, 2014
    The comment has been removed

  • Anonymous
    March 02, 2015
    what must be done to use the same process to use twitter streaming api in webpage?If possible can you help me or create a new post explaining. really appreciate any help Thank you

  • Anonymous
    March 27, 2015
    @Avinash I had the same question.  Check this out: www.tugberkugurlu.com/.../streaming-with-newnet-httpclient-and-httpcompletionoption-responseheadersread