Using OAuth with Twitter in Cocoa/Objective-C

Lately OAuth is getting pretty popular. Several websites are adopting it as the preferred authentication mechanism for their APIs, and most of them as the only one. So what exactly is OAuth, and what does it do? According to the official website:

This is what OAuth does, it allows the you the User to grant access to your private resources on one site (which is called the Service Provider), to another site (called Consumer, not to be confused with you, the User). While OpenID is all about using a single identity to sign into many sites, OAuth is about giving access to your stuff without sharing your identity at all (or its secret parts).

Basically, OAuth is a way to authenticate to a webservice without having to store the user’s password, and in most cases without even having to ask the user for it. Twitter adopted OAuth for its API, and as of August 16th, it’ll be the only way to use the API. In this post I will explain how to use OAuth to authenticate with Twitter in Cocoa/Objective-C.

Choosing the authentication method

Twitter offers us three ways to authenticate using OAuth. The first, mostly for web applications, is to send a callback URL with your request, so after the user authorizes your application he gets redirected to the callback URL, and your app can proceed from that. The second, directed to desktop and mobile applications, is to use out-of-band authentication: after authorization, Twitter provides the user with a PIN code that he can type in your app to proceed. And the third one is to send the user’s login and password via xAuth. Although it may seem easier to use the last option, Twitter considers it the least desired way (as the user still has to type his password in your app), and to use it you need to directly ask Twitter for permission, sending details about your app and why you want to use it to api@twitter.com. In this guide we’ll use out-of-band/PIN code authentication, since this method doesn’t require you to set up a callback URL or ask Twitter for permission.

Getting started

First things first: if you haven’t done yet, go to Twitter Application Platform and register your app to use OAuth (yes, you can register a test application, no need for approval). After registering, write down the Consumer key and the Consumer secret for your app, as you’ll need them in a moment.

In this sample project, I’m using OAuthConsumer to handle OAuth requests. There are two versions available, this one I linked to was modified to handle Twitter’s PIN code. Be warned that there’s a bug on its code: in line 214 of OAMutableURLRequest.m, it should read:

if (token.verifier != nil && ![token.verifier isEqualToString:@""]) {

I will eventually submit this fix to the author, but right now you can just change it yourself or use the version bundled with my code sample that you can download at the end of this post. It took me hours to figure that out.

Update: thanks to Raphael Caixeta, I noticed I linked to the wrong version of OAuthConsumer (there are several different forks). He kindly created a ZIP file with the correct version, and you can download it here.

Twitter’s OAuth authentication (using a PIN code) is a three step process. First you ask for a Request Token, then you redirect the user to a webpage so he can authorize your app and get the PIN code, and finally you ask for an Access Token. After that you just have to use that Access Token to sign every request you make.

Request Token

Less talk, more code. Here we go:

OAConsumer *consumer = [[OAConsumer alloc] initWithKey:@"CONSUMER_KEY"
                                                secret:@"CONSUMER_SECRET"];

OADataFetcher *fetcher = [[OADataFetcher alloc] init];

NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/oauth/request_token"];

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

[request setHTTPMethod:@"POST"];

[fetcher fetchDataWithRequest:request
                     delegate:self
            didFinishSelector:@selector(requestTokenTicket:didFinishWithData:)
              didFailSelector:@selector(requestTokenTicket:didFailWithError:)];

First, we create an OAConsumer object, using the consumer key and secret Twitter gave us (don’t forget to replace CONSUMER_KEY and CONSUMER_SECRET with the ones you got earlier). Then we create an OAMutableURLRequest using this consumer and Twitter’s Request Token URL. We set the request to use HTTP POST and finally use an OADataFetcher to submit it. This call uses two delegate methods for success and fail. Here’s the code for the success method:

- (void) requestTokenTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data
{
    if (ticket.didSucceed)
    {
        NSString *responseBody = [[NSString alloc] initWithData:data
                                                       encoding:NSUTF8StringEncoding];

        accessToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody];

        NSString *address = [NSString stringWithFormat:
                             @"https://api.twitter.com/oauth/authorize?oauth_token=%@",
                             accessToken.key];

        NSURL *url = [NSURL URLWithString:address];
        [[NSWorkspace sharedWorkspace] openURL:url];
    }
}

We get the response body and use the initWithHTTPResponseBody method from OAToken to create our Request Token. Then we use the token key and redirect the user to a Twitter page where he can authorize our app and get the PIN code. This is what the user will see:

Twitter Authorization

After authorizing, Twitter will give the user a PIN code (7 digits) that he should write or copy. We’ll use this PIN code in the next step.

Access Token

To get the Access Token the code is pretty similar:

OAConsumer *consumer = [[OAConsumer alloc] initWithKey:@"CONSUMER_KEY"
                                                secret:@"CONSUMER_SECRET"];

OADataFetcher *fetcher = [[OADataFetcher alloc] init];

NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/oauth/access_token"];

[accessToken setVerifier:@"PIN_CODE"];

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

[request setHTTPMethod:@"POST"];

[fetcher fetchDataWithRequest:request
                     delegate:self
            didFinishSelector:@selector(accessTokenTicket:didFinishWithData:)
              didFailSelector:@selector(accessTokenTicket:didFailWithError:)];

Now we use the PIN code as the verifier in our token. Then, in our request, we send the token we got earlier (now including the PIN code). Everything else is pretty much the same. Here’s the new success delegate method:

- (void) accessTokenTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data
{
    if (ticket.didSucceed)
    {
        NSString *responseBody = [[NSString alloc] initWithData:data
                                                       encoding:NSUTF8StringEncoding];

        accessToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody];
    }
}

Easy, right? We just get the response body and recreate our token using the new data. This new token is everything we need to sign our requests from now on. As long as you keep this token, you should never have to authorize your app again. The OAToken class even provides you with methods to store and retrieve this token, so you can keep it after closing your app and starting again.

Now you can go ahead and use any Twitter API method you want. Here’s an example to request the user’s home timeline:

OAConsumer *consumer = [[OAConsumer alloc] initWithKey:@"CONSUMER_KEY"
                                                secret:@"CONSUMER_SECRET"];

OADataFetcher *fetcher = [[OADataFetcher alloc] init];

NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/home_timeline.xml"];

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

[fetcher fetchDataWithRequest:request
                     delegate:self
            didFinishSelector:@selector(apiTicket:didFinishWithData:)
              didFailSelector:@selector(apiTicket:didFailWithError:)];

Sample Project

As you probably noticed, this post contains only code directly related to what I’m trying to explain. If you want the whole thing (including my modified OAuthConsumer) I’ve created a sample project including all the methods I used here and a very basic interface with some buttons you can use to call each method (and fields for consumer key, consumer secret and the PIN code).

Download the sample project for this post: OAuthDemo.zip (57 KB)

The sample project requires Mac OS X 10.5 (Leopard).