Monday, 10 June 2013

Twitter OAuth Cocoa

Twitter require OAuth1.0a authorisation for any access to their API as of June 2013.  Mark in Oregon's blog post is a really easy introduction to the horror of OAuth.  This post describes how I added this facility to an OSX application written in Objective-C using XCode.

Step 1: Authorise your application

  • Go to dev.twitter.com
  • Click on the down arrow next to your user image and select My Applications
  • Click on the Create New Application button
  • Write down all of the tokens and URLs
  • Create an access token using your own twitter account
  • Write down your access tokens

After that I had the following information:
  • Consumer Key: long alphanumeric code
  • Consumer Secret: longer alphanumeric code
  • Request token URL: https://api.twitter.com/oauth/request_token
  • Authorize URL: https://api.twitter.com/oauth/authorize
  • Access token URL: https://api.twitter.com/oauth/access_token
  • Callback URL: None
  • MyAccount Access token (oauth_token): really long alphanumeric code
  • MyAccount Access token secret (oauth_token_secret): longer alphanumeric code

Step 2: Code

I did a lot of research on OAuth libraries in general and Twitter specific OAuth too.  There's not a lot our there for Mac, most Objective-C libraries are for iOS which need a lot of porting or old and full of deprecated stuff.  I think Mac OSX Mountain Lion (10.8) could use SLRequest and ACAccount to do this but I'm on Mac OSX Lion (10.7).

Eventually I found a blog post by Rodrigo on OAuth for Twitter in Cocoa that really pointed me in the right direction which was OAuthConsumer.  I frigged it a bit to use the accessTokens I generated for my own account on dev.twitter.com under My Applications.  Eventually I will implement a full accessToken request process which will be useful for stopping unauthorized use of Chrysanthemum because I can reset the tokens on Twitter.  This is done by sending multiple fetcher requests with different urls, keys and secrets.

Looking at Rodrigo's code it slowly became clear.  Having added the right files to my XCode project from OAuthConsumer, the code went something like this:

OAToken *accessToken = [[OAToken alloc] initWithKey:@"access_token"
secret:@"access_token_secret"];

OAConsumer *consumer = [[OAConsumer alloc] initWithKey:@"consumer_token"
secret:@"consumer_token_secret"];
OADataFetcher *fetcher = [[OADataFetcher alloc] init];

OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:OAurl
consumer:consumer
token:accessToken
realm:nil
signatureProvider:nil];

[request setHTTPMethod:@"GET"];
[fetcher fetchDataWithRequest:request
delegate:self
didFinishSelector:@selector(apiTicket:didFinishWithData:)
didFailSelector:@selector(apiTicket:didFailWithError:)];
Then I added the two selectors:
- (void) apiTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data
{
    if (ticket.didSucceed)
    {
        NSError *error;
        jsonResponse = [NSJSONSerialization JSONObjectWithData:data
                                                       options:0
                                                         error:&error];
    } else {
        NSLog(@"API call did not succeed.");
    }
}
- (void) apiTicket: (OAServiceTicket *)ticket didFailWithError:(NSError *)error
{
    if (!ticket.didSucceed)
    {
        NSLog(@"Getting Twitter search failed: %@", [error localizedDescription]);
    }
}
Done!! The jsonResponse variable contains the results of my search!
NB If you're using ARC you will have to add -fno-objc-arc compiler flags to the OAuthConsumer files.

Some links that may be useful for 10.8 users (and me if I ever upgrade!) about SLRequest.

http://developer.apple.com/library/ios/#documentation/Social/Reference/SLRequest_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40012234
https://dev.twitter.com/docs/ios/making-api-requests-slrequest
http://www.profit.seohost.eu/video/video/4Syky2JmX9M/Social-Framework-Tutorial-Xcode-4-5-1.html
http://stackoverflow.com/questions/14573711/using-social-framework-and-slrequest-with-field-expansion
https://dev.twitter.com/docs/ios/making-api-requests-slrequest
http://developer.apple.com/library/ios/#documentation/Accounts/Reference/ACAccountClassRef/Reference/Reference.html#//apple_ref/doc/uid/TP40011019
http://developer.apple.com/library/ios/#documentation/Social/Reference/SLRequest_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40012234
http://www.dvlup.com/Community/View/14276293?sort=newest&tag=slrequest
https://dev.twitter.com/docs/auth/application-only-auth