Twitter OAuth: Simple cURL requests for your own data

Having to include an entire PHP OAuth library every time I want to make a simple API request for some of my own data from a 3rd party app like Twitter really pisses me off. Perhaps this is unreasonable, but it's a problem I ran into for the 4th or 5th time today when trying to help John O'Nolan fetch his status count for his blog.

Making a REST API request for your own twitter info using the "user/show" request is relatively simple as it doesn't actually require authentication. That is until you upload the code to your server and discover that someone else sharing the server's IP is very selfishly hogging all of the API requests.

Twitter very helpfully allows you to authenticate your own app for your account and generate an OAuth Access token, meaning you can skip the first few steps of the OAuth process. However after much Googling, I discovered there really aren't that many examples of what to do next - they all seem to use one or another library - which seems totally unnecessary for making one request.

After much searching, finally I found one awesome step-by-step tutorial which explains the first few steps of OAuth and in particular how to build the OAuth HTTP headers and OAuth signature to sign the request. So I've taken lead from here, borrowed the helper functions and signature code, and put it all together to make a signed GET request to the API and return some ACTUAL data.

Here's the couple of helper functions I borrowed, the first combines the request URI and parameters into a string as required by the OAuth signature. The second one takes an array of OAuth credentials/settings and combines them into the HTTP header for use with cURL.

function buildBaseString($baseURI, $method, $params)
{
    $r = array(); 
    ksort($params);
    foreach($params as $key=>$value){
        $r[] = "$key=" . rawurlencode($value); 
    }
    return $method."&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r)); 
}

function buildAuthorizationHeader($oauth)
{
    $r = 'Authorization: OAuth '; 
    $values = array(); 
    foreach($oauth as $key=>$value)
        $values[] = "$key="" . rawurlencode($value) . """; 
    $r .= implode(', ', $values); 
    return $r; 
}

Next you need to setup all of the OAuth credentials and settings. For Twitter, the tokens, keys and secrets you need will all be available on your App page. If you haven't got any Apps, you'll need to create one, authorise it for your account and grab an access token.

$url = "http://api.twitter.com/1/account/totals.json";

$oauth_access_token = "YOUR TOKEN HERE";
$oauth_access_token_secret = "YOUR TOKEN SECRET HERE";
$consumer_key = "YOUR KEY HERE";
$consumer_secret = "YOUR SECRET HERE";

$oauth = array( 'oauth_consumer_key' => $consumer_key,
                'oauth_nonce' => time(),
                'oauth_signature_method' => 'HMAC-SHA1',
                'oauth_token' => $oauth_access_token,
                'oauth_timestamp' => time(),
                'oauth_version' => '1.0');

The tricky bit, that doesn't ever seem to be explained to well, is creating the OAuth signature. For HMAC-SHA1, this boils down to the following few lines:
Create your URI base string by combining the URL you will be sending the request to with the oauth details as per the helper function. The key is the consumer secret and access token secret URL encoded and combined with an ampersand. Finally, the base url and the composite key are hashed and and base 64 encoded. Sounds really fraking complicated when you read the instructions, doesn't look so bad when it's written out in PHP.

$base_info = buildBaseString($url, 'GET', $oauth);
$composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret);
$oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
$oauth['oauth_signature'] = $oauth_signature;

To make the request we have to setup a HTTP header and a few other options to pass to cURL. The helper method does the hard work of creating the correct header format with the OAuth settings and then finally, it's time to make the request with cURL.

$header = array(buildAuthorizationHeader($oauth), 'Expect:');
$options = array( CURLOPT_HTTPHEADER => $header,
                  CURLOPT_HEADER => false,
                  CURLOPT_URL => $url,
                  CURLOPT_RETURNTRANSFER => true,
                  CURLOPT_SSL_VERIFYPEER => false);

$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);

$twitter_data = json_decode($json);

This works really well if you just want to fetch data from your own account - last statuses, mentions, favourites or your stats like in the example above. It should also work with any OAuth based API which supports HMAC-SHA1 signatures (Google, LinkedIn, Vimeo, the list goes on). If the API you're working with doesn't have a neat tool for getting an access token for your account like Twitter does, you can always do the first few authentication steps by using an online client. Fill out your details and it will handle the first few exchanges, and once you have your access token you're free to make requests using just the 50 lines of code above, instead of requiring an OAuth library.

Download the full Twitter OAuth Code Example

Big Kudos to Jason Graves (aka. GodLikeMouse) for putting his excellent PHP OAuth tutorial on the web.