Sunday 17 April 2011

Twitter integration using OAuth

So my Rankington application hosted on Google App Engine wants to read tweets containing mentions of keyword 'rankington' and also update the status of the Twitter system user Rankington on certain occations. There are loads of Twitter APIs out there for Java. Here's a short guide on how get going with Twitter4j and some handy knowledge of OAuth.

Download Twitter4j from http://twitter4j.org/en/index.html. If you wish to do only reads against Twitter you don't need to authenticate in any way, but if you wish to post status updates or similar you must provide credentials for the Twitter user you are using. In the past you could authenticate against the Twitter REST APIs using user/password but this has been shut down by Twitter since August 2010. So don't try that via the Twitter4J API which has not deprecated that code yet.

OAuth
Twitter is now using OAuth as access mechanism. If you are familiar with OpenID you could compare OAuth to OpenID in the sense that OpenID is a decentralised identification infrastructure, whereas OAuth solves authorisation in a decentralised way. OAuth is a RFC under standardization of the IETF. For example the Google Docs API and other Google APIs have recently added OAuth as access restriction mechanims for their REST APIs.

An example of using OAuth would be that you have some resources on a site A, say some private photos. You wish to let another site B access those photos in order to incorporate them into a photo stream or whatever, but you don't want to hand your identification credentials for site A to site B for obvious security reasons. Instead you wish to delegate authorisation to site B to access resources on site A.

What will happen is that site A and site B shares a common OAuth secret. Without going into the handshaking details you will surf against site B and an authorisation request will redirect you to site A where you will be asked to grant site B permission to the appropriate resources. Once redirecting back to site B, an OAuth token will be handed to site B which can be used from now on to access precisely the set of resources granted from site A using the access token. Check out the RFC if interested at http://tools.ietf.org/html/rfc5849.

Twitter4J and OAuth
So, in our case, Twitter is site A and Rankington is site B (service provider and client). To create the shared secret which will be generated by site A (= Twitter), go to http://twitter.com/oauth_clients/new and create a pair of secret keys. A consumer key and a consumer secret. 


A very basic test of this could be:

public class TwitterBridge {
    
    private static String key = "abcaasdkj1231231lkj123";
    private static String secret = "asdkj7987asdjl12312lkj4323423423";
    
    public static void main(String[] argv) throws TwitterException {

        Twitter twitter = new TwitterFactory().getInstance();
        twitter.setOAuthConsumer(key, secret);
        RequestToken requestToken = twitter.getOAuthRequestToken();
        System.out.println(requestToken.getAuthorizationURL());
        
        // Breakpoint here and update value of pin from what
        // what you get in browser when surfing against
        // authorisation URL above.
        String pin = "7117195";
        
        AccessToken accessToken = twitter.getOAuthAccessToken(requestToken, pin);
        
        System.out.println("Token: " + accessToken.getToken());
        System.out.println("Token secret: " + accessToken.getTokenSecret());
        
        Query query = new Query();
        query.setQuery("rankington");
        
        QueryResult queryResult = twitter.search(query);
        
        List<Tweet> tweets = queryResult.getTweets();
        for (Tweet t : tweets) {
            System.out.println("From: " + t.getFromUser());
            System.out.println("Time: " + t.getCreatedAt());
            System.out.println("Text: " + t.getText());
        }
        
        twitter.updateStatus("New tweet!");
    }
}
So put in your consumer key and secret in the code above as key and secret. Then debug these lines of code.

System.out.println(requestToken.getAuthorizationURL());

will print something like
http://api.twitter.com/oauth/authorize?oauth_token=51IMwiqF8MfEdcNDZxzUgV3guqCpQK6VbFZasdl





Open that link in a browser and you will be prompted
to identify yourself against Twitter, unless you are logged in automatically. In the same dialog you allow the client application "rankington" to access Twitter in your stead.

A bit confusingly, we login as user "rankington" on Twitter and allow application "rankington" access. This is just conincidence that the names are the same in this example.

When granted access, a verification code will be shown. Copy this code and either rerun the Java program or insert it into via the debugger as the variable "pin".

Continue to run the program and the Twitter4J API will verify the pin code against the Twitter REST API and receive an access token. We print this and it will look something like

Token: 45335176-3NEtmOsdfsacZROM9ow3sdfsdfHm5dfu0ShNGTdN2CKw
Token secret: nOXQish8asfasiq4tZINEOJuDasdYDQC4dBJiAM3k

All good. These are the important values which we can use to create a new AccessToken in the future.
The end of the program makes a query for tweets concerning status updates containing "rankington". That would print:

From: rankington
Time: Sun Apr 17 01:10:48 CEST 2011
Text: Rankington alpha is out! Follow progress at http://macgyverdev.blogspot.com
#rankington

And in the end, the program makes a status update in the name of the Twitter user "rankington".

So, now we got all ingredients, all keys and secrets for OAuth authority delegation. The piece of code we can use in our real application is the following.

private static String key         = "3649LZ3sasdasdpXWFHkHxaWQQ";
   private static String secret      = "aFOb86GmafgKtTasdasq3CpcwQw7bA";
   private static String token       = "28326asdasdasdD1ZxVDDL5Mqe7H";
   private static String tokensecret = "7Klyasdasdasdwpc8Xbtm0IsiRA";

   public static void main(String[] argv) throws TwitterException {
        
        AccessToken accessToken = new AccessToken(token, tokensecret);
        
        ConfigurationBuilder confBuilder = new ConfigurationBuilder(); 
        confBuilder.setOAuthAccessToken(accessToken.getToken()) 
                   .setOAuthAccessTokenSecret(accessToken.getTokenSecret()) 
                   .setOAuthConsumerKey(key)
                   .setOAuthConsumerSecret(secret); 

        Twitter twitter = new TwitterFactory(confBuilder.build()).getInstance(); 
        
        Query query = new Query();
        query.setQuery("rankington");
        
        QueryResult queryResult = twitter.search(query);
        
        List tweets = queryResult.getTweets();
        for (Tweet t : tweets) {
            System.out.println("From: " + t.getFromUser());
            System.out.println("Time: " + t.getCreatedAt());
            System.out.println("Text: " + t.getText());
        }
        
        twitter.updateStatus("New tweet again!");
    }

You see that we create the AccessTokens needed to authenticate against Twitter using the keys and secrets previously negotiated as a one time routine. The application can now tweet in eternity unless the user revokes the authorisation for the client.

With my basic understanding of OAuth, it feels like a great standard for interconnecting all service providers we got in the cloud. 

3 comments:

  1. I can't find the ConfigurationBuilder class. I'm using Twitter4J version 2.1.1. Where can i find it? Can u help me, Johan?

    ReplyDelete
  2. Hi Jota. I'm also using Twitter4J 2.1.1. Are you having compile time or runtime problems? If you can't find it in compile time, make sure you have the twitter4j-core-2.1.1.jar on your classpath.
    Depending on your deployment, you should have that jar file in your MANIFEST.MF to be able to classload it in runtime if you run it standalone.

    I use Maven for my build so I've added this to my pom.xml to get the Twitter4J stuff


    <dependency>
    <groupId>net.homeip.yusuke</groupId>
    <artifactId>twitter4j</artifactId>
    <version>2.0.10</version>
    <type>jar</type>
    <scope>compile</scope>
    </dependency>


    but I guees you can find the jar at
    http://twitter4j.org/en/index.html#download

    Cheers!

    ReplyDelete
  3. Your contents are too simple to read and easy to understand.
    -----------------------------------------------------------------------------
    Android Application Developer India & Android Application Development Company

    ReplyDelete