Click here to Skip to main content
Click here to Skip to main content

Using OAuth for Twitter Authentication on the BlackBerry PlayBook

, 18 Apr 2011
Rate this:
Please Sign up or sign in to vote.
I had some difficulty wrapping my head around OAuth the first few times I tried to use it so I’ll provide a quick explanation below as I walk through the sample.

OAuth is becoming critical for any app developer who wants to access data from a 3rd party source on behalf of their users. If you aren’t familiar with OAuth there is an excellent intro doc over at Hueniverse.

OAuth is a way of providing access from a 3rd party site (in this case Twitter) to your application without needing the user to type their 3rd party credentials into your application. Instead, OAuth lets you register with the 3rd party site and uses a series of tokens, which eventually give you access to the data. One of the main benefits with OAuth is that if an application does something nefarious with the data, the user can immediately revoke access. For this example I’ll be walking through the Twitter API and using the very excellent OAuth-AS3 library by Shannon Hicks, the founder of Pintley, which you should check out if you’re the kind of person who likes to drink beer.

The first step to using OAuth is to register with the site you want to get data from. Twitter has a very easy way to do this with their App portal. Fill in the necessary info (select the type as client since this won’t be a web-based application) and Twitter will provide a bunch of random strings that you’ll use to request access to the data and then request the data itself. The data that we’re most worried about is in the OAuth 1.0a Settings section and includes a consumer key, consumer secret, request token URL, access token URL, and authorize URL.

Getting information out of Twitter has the following flow:

  1. Use the consumer key and the consumer secret to create an OAuthConsumer object.
  2. Use the OAuthConsumer object to ask Twitter for permission to access data.
  3. Prompt the user to authorize your application to access their specific data.
  4. Request the user’s data and perform operations on their behalf.

This is all done with a series of tokens until the last stage when you get an access token that you will use to access data after the user gives you permission. I set those up as private field variables so they can be accessed from any method in this example and set the unchanging data as static variables.

private static var CONSUMER_SECRET:String = "<YOUR CONSUMER SECRET>";
private static var CONSUMER_KEY:String = "<YOUR CONSUMER KEY>";
private static var REQUEST_TOKEN_URL:String = 
    "https://api.twitter.com/oauth/request_token";
private static var ACCESS_TOKEN_URL:String = "https://api.twitter.com/oauth/access_token";
private static var AUTHORIZE_URL:String = "https://api.twitter.com/oauth/authorize";
private static var API_URL:String = "https://api.twitter.com";
private static var SIGNATURE:OAuthSignatureMethod_HMAC_SHA1 = 
    new OAuthSignatureMethod_HMAC_SHA1();
 
private var _consumer:OAuthConsumer;
private var _authRequest:OAuthRequest;
private var _accessRequest:OAuthRequest;
 
private var _requestToken:OAuthToken;
private var _accessToken:OAuthToken;

The first step is to have our application log into Twitter with the consumer secret and the consumer key so that it can make the authorization request. In the init() function I set up the UI as well as create the consumer and my first OAuthRequest object, the authorization request. This will just go out to Twitter and make sure that the consumer key and secret are registered to an application. If they are, then Twitter will return a request token that I can use to request access from the user for his or her data. In that init() method I have a button that will start the process and the event handler on the button uses the buildRequest method of my _authRequest object to format the URL string correctly and then I send it off to Twitter.

protected function init():void
{    
     _consumer = new OAuthConsumer(CONSUMER_KEY,CONSUMER_SECRET);
     _authRequest = new OAuthRequest(OAuthRequest.HTTP_MEHTOD_GET,REQUEST_TOKEN_URL,
         null,_consumer);
 
     _loginContainer = new Container();
     _loginContainer.align = ContainerAlign.MID;
 
 
 
     var button:LabelButton = new LabelButton();
          button.label = "Login to Twitter";
          button.addEventListener(MouseEvent.CLICK,onClick);
 
 
     _loginContainer.addChild(_spacer);
     _loginContainer.addChild(button);
     _loginContainer.setSize(1024,600);
     addChild(_loginContainer);
 
}
 
protected function onClick(event:MouseEvent):void
{
     var urlRequest:URLRequest = new URLRequest(_authRequest.buildRequest(SIGNATURE));
     var loader:URLLoader = new URLLoader(urlRequest);
     loader.addEventListener(Event.COMPLETE,onRequestComplete);
}

With that response I can now build the _requestToken, which I can use to let the user grant me access to his or her data. The next step is to prompt the user to authorize my application. Once I get the response back from Twitter’s servers I save that information as the request token and then build a UI to let the user start the authorization process.

protected function onRequestComplete(event:Event):void
{
     _requestToken = getTokenFromResponse(event.currentTarget.data);
 
     _authContainer = new Container();
     _authContainer.align = ContainerAlign.MID;
 
 
     var authBtn:LabelButton = new LabelButton();
          authBtn.label = "Authorize this application";
          authBtn.addEventListener(MouseEvent.CLICK,onAuthClick);
 
     _authContainer.addChild(_spacer);
     _authContainer.addChild(authBtn);
     _authContainer.setSize(1024,600);
 
     removeChild(_loginContainer);
     addChild(_authContainer);
}

When the user clicks the button my application will send them to Twitter where they will have to log in and authorize my application to use their data. They’re prompted either to deny my app or allow it.

authorize_twitter.png

If they click Allow, then Twitter provides a PIN number that the user has to enter back in the application to complete the authorization process. For web-based applications there is a callback URL which is where the user is sent after they authorize the application. But for client-side applications, Twitter uses the PIN number and asks the user to enter it back in the application.

twitter_pin_entry.png

In the code, I first create the UI elements I need to track the PIN number and then make a URLRequest using the key that Twitter provided in the request token.

protected function onAuthClick(event:MouseEvent):void
{
     _verifyContainer = new Container();
     _verifyContainer.align = ContainerAlign.MID;
 
     var label:Label = new Label();
          label.size = 100;
          label.sizeUnit = SizeUnit.PERCENT;
          label.text = "Enter the PIN from Twitter.com";
 
     var font:TextFormat = new TextFormat();
          font.align = TextFormatAlign.CENTER;
          font.bold = true;
          font.size = 24;
 
     text = new TextField();
     text.type = TextFieldType.INPUT;
     text.border = true;
     text.width = 250;
     text.height = 30;
     text.defaultTextFormat = font;
 
 
     var getDataBtn:LabelButton = new LabelButton();
          getDataBtn.label = "Get Tweets";
          getDataBtn.addEventListener(MouseEvent.CLICK,onGetDataClick);
 
     _verifyContainer.addChild(_spacer);
     _verifyContainer.addChild(label);
     _verifyContainer.addChild(text);
     _verifyContainer.addChild(getDataBtn);
     _verifyContainer.setSize(1024,600);
 
 
     removeChild(_authContainer);
     addChild(_verifyContainer);
 
     var authRequest:URLRequest = new URLRequest(
         'http://api.twitter.com/oauth/authorize?oauth_token='+_requestToken.key);
     navigateToURL(authRequest);
}

Once the user comes back, puts in the PIN, and clicks the button, the application uses that information to build the request for the access token. By passing the PIN as the oauth_verifier property we get the access token we need to start requesting data from Twitter.

protected function onGetDataClick(event:MouseEvent):void
{
     var params:Object = new Object();
          params.oauth_verifier = text.text;
 
     _accessRequest = new OAuthRequest(OAuthRequest.HTTP_MEHTOD_GET,
         ACCESS_TOKEN_URL,params,_consumer,_requestToken);
 
     var accessUrlRequest:URLRequest = new URLRequest(
         _accessRequest.buildRequest(SIGNATURE));
     var accessLoader:URLLoader = new URLLoader(accessUrlRequest);
          accessLoader.addEventListener(Event.COMPLETE,onAccessRequestComplete);
}
 
protected function onAccessRequestComplete(event:Event):void
{
     _accessToken = getTokenFromResponse(event.currentTarget.data);
 
     var mainRequest:OAuthRequest = new OAuthRequest(
         OAuthRequest.HTTP_MEHTOD_GET,API_URL+'/1/statuses/friends_timeline.xml',
         null,_consumer,_accessToken);
 
     var getStatusURLRequest:URLRequest = new URLRequest(
         mainRequest.buildRequest(SIGNATURE));
     var getStatusLoader:URLLoader = new URLLoader(getStatusURLRequest);
          getStatusLoader.addEventListener(Event.COMPLETE,onStatusLoadComplete);
}

Requesting data is pretty straightforward. Using the consumer and access tokens we just got we can build a normal request, send it off, and then parse the data that comes back. In this case I’m going to go through and display usernames and status for the tweets.

protected function onStatusLoadComplete(event:Event):void
{
     _mainContainer = new Container();
     _mainContainer.flow = ContainerFlow.HORIZONTAL;
 
     var sendTweetContainer:Container = new Container(25);
          sendTweetContainer.containment = Containment.DOCK_TOP;
 
     var font:TextFormat = new TextFormat();
          font.align = TextFormatAlign.CENTER;
          font.bold = true;
          font.size = 24;
 
     twitterTextField = new TextField();
     twitterTextField.type = TextFieldType.INPUT;
     twitterTextField.border = true;
     twitterTextField.width = 500;
     twitterTextField.height = 30;
     twitterTextField.defaultTextFormat = font;
 
     var tweetLabel:LabelButton = new LabelButton();
          tweetLabel.label = "Tweet This";
          tweetLabel.addEventListener(MouseEvent.CLICK,onTweetClick);
 
          sendTweetContainer.addChild(twitterTextField);
          sendTweetContainer.addChild(tweetLabel);
 
     // Code for parsing the XML from the response
     var xml:XML = new XML(event.currentTarget.data);
     var statusList:XMLList = xml.children();
     var arr:Array = new Array();
 
     for(var i:int=0;i<statusList.length();i++)
     {
          var obj:Object = new Object();
               obj.label = statusList[i].user.name.toString() +': ' + 
               statusList[i].text.toString();
          arr.push(obj);
     }
 
     // Create the DataProvider out of the parsed data
     var dataProvider:DataProvider = new DataProvider(arr);
     var list:List = new List();
          list.dataProvider = dataProvider;
          list.size = 100;
          list.sizeUnit = SizeUnit.PERCENT;
          list.setSkin(AlternatingCellRenderer);
 
 
     _mainContainer.addChild(list);
     _mainContainer.addChild(sendTweetContainer);
     _mainContainer.setSize(1024,600);
     removeChild(_verifyContainer);
     addChild(_mainContainer);
}

The next step is to enable the ability to send a tweet. This one is a bit different. For all of the previous calls we just created a params object, and sent that with the OAuthRequest. But when we’re using POST instead of GET, things have to be done differently. Soenke Rohde has a Flash Twitter library that I used for help, but essentially we have to strip the URL params from the original request and then reset them as URLVariables to match the POST request.

protected function onTweetClick(event:MouseEvent):void
{
     var params:Object = new Object();
          params.status = twitterTextField.text;
 
     // Use the same consumer and accessToken to update the Status
     var tweetRequest:OAuthRequest = new OAuthRequest(
         OAuthRequest.HTTP_MEHTOD_POST,API_URL+'/1/statuses/update.json',
         params,_consumer,_accessToken);
 
     var setStatusURLRequest:URLRequest = new URLRequest(tweetRequest.buildRequest(
          SIGNATURE));
          setStatusURLRequest.method = URLRequestMethod.POST;
 
          // use the replace function to strip out the status
          setStatusURLRequest.url = setStatusURLRequest.url.replace("&status=" + 
              URLEncoding.encode(params.status),"");
 
     // Add the status as a URLVariable since it's a POST operation
     setStatusURLRequest.data = new URLVariables( "status=" + twitterTextField.text  );
 
     var setStatusLoader:URLLoader = new URLLoader(setStatusURLRequest);
          setStatusLoader.addEventListener(Event.COMPLETE,onSetStatusComplete);
}

And that’s pretty much all there is to it. You can grab the whole bit of code over on Snipplr. Just swap in your own information from Twitter and you should be set to go.

One thing to keep in mind is that this example makes you authorize each time you use the application. In reality that would be very annoying so if you were using this in production you’d want to save the consumer and accessToken somewhere so you didn’t have to create those each time.

Related posts:

  1. Creating Custom List Skins for the BlackBerry PlayBook
  2. Setting Custom Labels on Lists with the PlayBook
  3. Using the Container Classes to Lay Out PlayBook Applications
  4. Problems with Accordian Containers in Flex
  5. Getting Started with the BlackBerry PlayBook and Adobe AIR

License

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

About the Author

Ryan Stewart

United States United States
No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 18 Apr 2011
Article Copyright 2011 by Ryan Stewart
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid