Philip Lippard

Please say it ain't so

Twitter Authentication, OAuth and Discontinued Support for Basic Authentication

I was recently excited when I learned that the ELMAHopen source component (which I use as one of many components to monitor web site behavior) had the ability to send alerts to a twitter account.  I was then disappointed to learn that it no longer worked, because ELMAH was using Basic Authentication with the Twitter account’s user ID and password; and Twitter had disabled Basic Authenticationsince around 1-Sep-2010.  Twitter has opted to implement the more secure OAuth authentication scheme.   OAuthis a new open standard for providing delegated secure access to private resources, better defined as follows:

“…OAuth allows you to share your private resources (photos, videos, contact list, bank accounts) stored on one site with another site without having to hand out your username and password. There are many reasons why one should not share their private credentials. Giving your email account password to a social network  site so they can look up your friends is the same thing as going to dinner and giving your ATM card and PIN code to the waiter when it’s time to pay. Any restaurant asking for your PIN code will go out of business, but when it comes to the web, users put themselves at risk sharing the same private information. OAuth to the rescue.

oauth_diagram

After reading several articles on the web regarding OAuth, I learned quickly that replacing Basic Authentication with OAuth would be more involved than changing a few lines of code.  In fact, it would probably be necessary to find a suitable open source OAuth library to do the heavy lifting.  I found a couple of solutions from Shannon Whitley and also one called OAuth.net.

In so much as I was only looking to re-enable ELMAH Twitter support, I simply wanted to authenticate myself with Twitter and send an occasional direct user message.  OAuth.net provides support for the Consumer (client) requiring authentication as well as the Service Provider for web sites needing to implement secure delegation of credentials.  On the other hand the Shannon Whitney open source solution primarily addressed the needs of the Consumer (client).

After much downloading, assembling and debugging I settled on the Shannon Whitney open source solution, however parts of it were out of date and/or not working; such as the Twitter URLs being used.   I have enhanced and extended the Shannon Whitney solution to more than adequately meet my requirement of authenticating myself with Twitter.

To get startedone needs to register their applicationwith a Twitter user account from which one expects to authenticate on behalf of.   The output of this application registration will be a Consumer Key string value and a Consumer Secret value.   Using my enhanced and extended OAuth library the Consumer Key and Consumer Secret are used as the minimum requirements to obtain an Access Token Set; consisting of an Access Token string value and an Access Token Secret.  This Access Token Set are the base credentials to be used by one’s third party application to authenticate with Twitter.  This Access Token Set should be securely stored as is the case with any set of credentials.  The owning and delegator Twitter user can change his/her password at any time without compromising the ability of the third party application to authenticate.  The owning and delegator Twitter user can also revoke the privileges of the third party application without compromising his/her Twitter account for continued use.

What is needed for demo purposes is a program to request the Access Token Set and store it for future use and then another program to demonstrate how the Access Token Set can be used repeatedly for authentication.

At the end of this article is a download link to download a project which contains all sample programs and supporting libraries.  The sample web transaction below from this project shows the process of taking a Consumer Key and Consumer Secret, using the enhanced OAuth library and obtaining the Access Token Set (Access Token and Access Token Secret).

   1:  using System;
   2:  using System.Data;
   3:  using System.Configuration;
   4:  using System.Collections;
   5:  using System.Web;
   6:  using System.Web.Security;
   7:  using System.Web.UI;
   8:  using System.Web.UI.WebControls;
   9:  using System.Web.UI.WebControls.WebParts;
  10:  using System.Web.UI.HtmlControls;
  11:  using System.IO;
  12:  using System.Text;
  13:   
  14:  namespace oAuthExample
  15:  {
  16:      public partial class _Default : System.Web.UI.Page
  17:      {
  18:          protected void Page_Load(object sender, EventArgs e)
  19:          {
  20:              string url = string.Empty;
  21:              string xml = string.Empty;
  22:              oAuthTwitter oAuth = new oAuthTwitter();
  23:   
  24:              if (Request["oauth_token"] == null)
  25:              {
  26:                  //Redirect the user to Twitter for authorization.
  27:                  //Using oauth_callback for local testing.
  28:                  oAuth.CallBackUrl = this.Request.Url.AbsoluteUri;
  29:                  Response.Redirect(oAuth.AuthorizationLinkGet());
  30:              }
  31:              else
  32:              {
  33:                  //Get the access token and secret.
  34:                  oAuth.AccessTokenGet(Request["oauth_token"], Request["oauth_verifier"]);
  35:                  if (oAuth.TokenSecret.Length > 0)
  36:                  {
  37:                      // Save my Access Token Set - place in Web.config for use with
  38:                      // DefaultWithToken.aspx
  39:                      using (StreamWriter sw =
  40:                          new StreamWriter(Request.MapPath("~/TwitterCredentials"), false))
  41:                      {
  42:                          sw.WriteLine("Token=" + oAuth.Token);
  43:                          sw.WriteLine("TokenSecret=" + oAuth.TokenSecret);
  44:                          sw.Flush();
  45:                      }
  46:   
  47:                      url = "http://api.twitter.com/1/direct_messages/new.json";
  48:                      string postData = "user=@MyTwitterAccount" +
  49:                          "&text=" + 
  50:                          oAuth.UrlEncode("D @MyTwitterAccount - Access Token Obtained");
  51:                      xml = oAuth.oAuthWebRequest(oAuthTwitter.Method.POST, url, postData);
  52:                      apiResponse.InnerHtml = Server.HtmlEncode(xml);
  53:                  }
  54:              }
  55:          }
  56:      }
  57:  }

The above web transaction will essentially record the Access Token Set to the TwitterCredentials file of the root directory.  The Access Token and Access Secret from the TwitterCredentials file should now be placed into the AppSettings of the web.config and then the next web transaction will demonstrate using such credentials for repeated use:

   1:  using System;
   2:  using System.Data;
   3:  using System.Configuration;
   4:  using System.Collections;
   5:  using System.Web;
   6:  using System.Web.Security;
   7:  using System.Web.UI;
   8:  using System.Web.UI.WebControls;
   9:  using System.Web.UI.WebControls.WebParts;
  10:  using System.Web.UI.HtmlControls;
  11:   
  12:  namespace oAuthExample
  13:  {
  14:      public partial class DefaultWithToken : System.Web.UI.Page
  15:      {
  16:          // Direct Message API - http://dev.twitter.com/doc/post/direct_messages/new
  17:          // Limits (403) - http://support.twitter.com/forums/10711/entries/15364
  18:          // Also returns 403 when you send same message twice...
  19:          protected void Page_Load(object sender, EventArgs e)
  20:          {
  21:              string url = string.Empty;
  22:              string xml = string.Empty;
  23:              oAuthTwitter oAuth = new oAuthTwitter();
  24:              oAuth.Token = ConfigurationManager.AppSettings["accessToken"];
  25:              oAuth.TokenSecret = ConfigurationManager.AppSettings["accessTokenSecret"];
  26:   
  27:              url = "http://api.twitter.com/1/direct_messages/new.json";
  28:              string postData = "user=@MyTwitterAccount" +
  29:                          "&text=" + oAuth.UrlEncode("D @MyTwitterAccount - Hello World");
  30:              xml = oAuth.oAuthWebRequest(oAuthTwitter.Method.POST, url, postData);
  31:              apiResponse.InnerHtml = Server.HtmlEncode(xml);
  32:          }
  33:      }
  34:  }

The web.config is shown as follows:

   1:  <?xml version="1.0"?>
   2:  <configuration>
   3:    <appSettings>
   4:      <add key="consumerKey"
   5:           value="XXXXXXXXXXXXXXXXXXXXXXXXX"/>
   6:      <add key="consumerSecret"
   7:           value="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"/>
   8:      <add key="accessToken"
   9:           value="YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"/>
  10:      <add key="accessTokenSecret"
  11:           value="YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"/>
  12:    </appSettings>
  13:      <connectionStrings/>
  14:      <system.web>
  15:      <compilation debug="true"
  16:                   targetFramework="4.0" />
  17:          <authentication mode="Windows"/>
  18:          <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/>
  19:    </system.web>
  20:  </configuration>

 

To protect the innocent, the web.config above does not show the actual Consumer Key and Consumer Secret as well as the actual Access Token and Access Token Secret.

That is it…Authentication with OAuth for Twitter…at least from the Consumer’s perspective.   Click HERE to download the project.

Loading