Monthly Archives: April 2011

Twitter OAuth PHP Tutorial

Foreword

Trying to get a dial tone with Twitter’s new OAuth can be a frustrating and daunting task.  Especially when it comes to the utter lack of proper documentation with regards to just connecting with to Twitter using OAuth.  This tutorial will walk you through the steps required to be able to make calls using Twitter’s OAuth in PHP.

Getting Started

OK, first things first.  You’ll need to have your web application registered with Twitter, as well as the associated username and password of the account.  If you haven’t registered your application with Twitter yet, here’s what you’ll need to do:

First visit http://dev.twitter.com/

Click on the “Register an app” link.

Then fill out all the appropriate information requested.  Make sure that you’ve selected “Browser” as your “Application Type”.

You will also need to register a callback URL.  This is the URL where people will be redirected to after they have authorized your website/application for use with their Twitter account.  This is also where you will receive validation information directly from Twitter which will be required to make calls on behalf of the Twitter user.

Once you have filled out the form and registered your application, you’ll be presented with the details of your registration including your “Consumer Key” and “Consumer Secret”.  You’ll be using those shortly so keep a browser instance open or copy them down.

Twitter Application Registration

Twitter Application Registration

Now that the prerequisites are done, it’s time to being the battle with OAuth.

Beginning OAuth

First let’s understand what needs to happen to get OAuth working.

The gist is simple enough, we need to create a header with authorization data in it.  Post it to Twitter, get a token back from twitter letting us know we’re registered and everything is groovy.  Next we’ll retrieve the authorization URL to allow users to authorize our application with their account and finally, do something…Uh Twittery, Twitter-esc…I don’t know, don’t ask.

Now, the most important thing to remember here is Twitter is super picky about how everything is encoded…super picky.  So if you make one mistake, you’ll get a forbidden and get rejected with very little help response message wise from Twitter.

So let’s start by getting the request token from Twitter, which will let us know we’re on the right track.

Getting The Request Token

To get the request token from Twitter we need to POST a call to:

https://api.twitter.com/oauth/request_token

But first we need to sign and encode an authorization header, and yes..it is a pain.  Lucky for you I’ve already been through this so you don’t have to deal with figuring it all out.  Here we go.

The authorization header required for the request token requires the following fields:

  • oauth_callback – the url to be redirected to after authorization
  • oauth_consumer_key – this is the consumer key you get after registering your application with Twitter
  • oauth_nonce – this is a unique value that you generate to reduce the chance of someone hijacking your session
  • oauth_signature_method – this is the method used to sign the base string, we’ll get to this in a bit, but for now the default value is “HMAC-SHA1”
  • oauth_timestamp – this is the current timestamp.
  • oauth_version – this is going to be “1.0”

An easy way to deal with the authorization header and it’s nuances is to load all the oauth header values into an associative array and pass them to functions that will sign, encode, etc.

$nonce = time();
$timestamp = time();
$oauth = array('oauth_callback' => 'http://yourdomain.com/callback_page',
              'oauth_consumer_key' => 'yourconsumerkey',
              'oauth_nonce' => $nonce,
              'oauth_signature_method' => 'HMAC-SHA1',
              'oauth_timestamp' => $timestamp,
              'oauth_version' => '1.0');

Just to clarify what I’ve done so far.  The $nonce variable can be pretty much whatever you want, I thought for the purpose of this tutorial however time() would be the easiest to understand.  The $timestamp, well that should be pretty obvious.  The $oauth is our associative array containing all the fields and values required to get us started.

Now that we have our oauth array, we need to create our base string.  The base string is basically a signature of the action we want to perform which later we will sign using HMAC-SHA1 and our composite key.  The result of which will be our oauth_signature.  I know it sounds a bit confusing, but don’t worry.  I’ll walk you through the entire process step by step.

So let’s build the base string.  The base string has the format of:

METHOD&BASEURI&OAUTH_PARAMS_SORTED_AND_ENCODED

For example, here’s a fully encoded base string:

POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_callback%3Dhttp%253A%252F%252Flocalhost%253A3005%252Fthe_dance%252Fprocess_callback%253Fservice_provider_id%253D11%26oauth_consumer_key%3DGDdmIQH6jhtmLUypg82g%26oauth_nonce%3DQP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1272323042%26oauth_version%3D1.0

Yeah, it’s ugly.  And here’s how you create it.  As I said before Twitter is very picky about encoding, etc.  So to ensure everything is encoded the same way each and every time, let’s use a function that will do it for use using our $oauth array.

/**
 * Method for creating a base string from an array and base URI.
 * @param string $baseURI the URI of the request to twitter
 * @param array $params the OAuth associative array
 * @return string the encoded base string
**/
function buildBaseString($baseURI, $params){
 
$r = array(); //temporary array
    ksort($params); //sort params alphabetically by keys
    foreach($params as $key=>$value){
        $r[] = "$key=" . rawurlencode($value); //create key=value strings
    }//end foreach                
 
    return 'POST&' . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r)); //return complete base string
}//end buildBaseString()

So here’s what the buildBaseString() function does.  It takes the $baseURI, in this case “https://api.twitter.com/oauth/request_token” and the $oauth array we created and hands back the encoded base string.  It does this by first sorting the $oauth array according to keys (this is required by Twitter, one of the gotchas), then it creates a “key=value” string using rawurlencode (i.e. oauth_signature=HMAC-SHA1, rawurlencode is another gotcha), then it creates and hands back the base string after yet another full rawurlencode of all the “key=value” strings (this was a major gotcha, took me forever to figure out).  I can’t stress enough how absolutely imperative it is that the base string gets created exactly like this.  Any deviation for this can easily result in forbidden/unauthorized rejections from Twitter.

Now that we have a way to create a base string let’s create one.

$baseString = buildBaseString($baseURI, $oauth);

And wallah, a base string…yay!  Now we need to sign it.  To sign the base string we’ll need to do a couple of things.  The first is to create the composite key.  The composite key is the result of a rawurlencode of the consumer secret separated by the “&” followed by the rawurlencode of the token.  Now, being that we are trying to retrieve the token we don’t have that just yet and it’s set to null.  But for all calls after we get our request token, we’ll need to make sure it is included in the composite key otherwise the call will be rejected.  Once again to make live easy, let’s create a function called getCompositeKey().

/**
 * Method for creating the composite key.
 * @param string $consumerSecret the consumer secret authorized by Twitter
 * @param string $requestToken the request token from Twitter
 * @return string the composite key.
**/
function getCompositeKey($consumerSecret, $requestToken){
    return rawurlencode($consumerSecret) . '&' . rawurlencode($requestToken);
}//end getCompositeKey()

That function is pretty self explanatory.  Now to actually sign the base string we’ll need to use the composite key, sign it with the binary form of HMAC-SHA1 and encode the result as base64.  This will create our oauth_signature which we will need to finalize our request to Twitter.  This is what you’ll need.

$consumerSecret = 'consumer-secret'; //put your actual consumer secret here, it will look something like 'MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98'
 
$compositeKey = getCompositeKey($consumerSecret, null); //first request, no request token yet
$oauth_signature = base64_encode(hash_hmac('sha1', $baseString, $compositeKey, true); //sign the base string
$oauth['oauth_signature'] = $oauth_signature; //add the signature to our oauth array

First we create our composite key by passing in the consumer secret that you received when you registered your application with Twitter.  We pass in null for the $requestToken argument because that’s what we’re going to retrieve.  Next we sign our base string.  Then add the $oauth_signature to our $oauth array to be used in our authorization header.  Now, let’s build us a header buddy…yee haw!

The header once constructed will need to have the following format:

Authorization: OAuth key=value, key=value, …

Once again, to make life easy, why don’t we build a function to build Authorization header for us.

/**
 * Method for building the OAuth header.
 * @param array $oauth the oauth array.
 * @return string the authorization header.
**/
function buildAuthorizationHeader($oauth){
    $r = 'Authorization: OAuth '; //header prefix
 
    $values = array(); //temporary key=value array
    foreach($oauth as $key=>$value)
        $values[] = "$key=\"" . rawurlencode($value) . "\""; //encode key=value string
 
    $r .= implode(', ', $values); //reassemble
    return $r; //return full authorization header
}//end buildAuthorizationHeader()

This function simply takes in the $oauth array and transforms it into the Authorization header format.  The only caveat here is that the values need to be wrapped in rawurlencode (yet another gotcha).  Now all that we really need to do is construct our header and place a call out to Twitter and get the request token back.  To make the request across the line to Twitter, I used cURL.  PHP makes it easy to use, so let’s wrap it in a function that we’ll use for all Twitter calls going forward.  Now there’s a bit of a gotcha here that’s undocumented (ofcourse).  When you build the header you will also need to pass in an “Expect: ” header option, otherwise Twitter will complain and fail.  Something like:

/**
 * Method for sending a request to Twitter.
 * @param array $oauth the oauth array
 * @param string $baseURI the request URI
 * @return string the response from Twitter
**/
function sendRequest($oauth, $baseURI){
    $header = array( buildAuthorizationHeader($oauth), 'Expect:'); //create header array and add 'Expect:'
 
    $options = array(CURLOPT_HTTPHEADER => $header, //use our authorization and expect header
                           CURLOPT_HEADER => false, //don't retrieve the header back from Twitter
                           CURLOPT_URL => $baseURI, //the URI we're sending the request to
                           CURLOPT_POST => true, //this is going to be a POST - required
                           CURLOPT_RETURNTRANSFER => true, //return content as a string, don't echo out directly
                           CURLOPT_SSL_VERIFYPEER => false); //don't verify SSL certificate, just do it
 
    $ch = curl_init(); //get a channel
    curl_setopt_array($ch, $options); //set options
    $response = curl_exec($ch); //make the call
    curl_close($ch); //hang up
 
    return $response;
}//end sendRequest()

Please  note: You may need to add CURLOPT_POSTFIELDS => ” depending on the version of PHP you are using. ~thanks to Thomas Krantz

So this function sends a request to Twitter (obviously), it constructs the header using the buildAuthorizationHeader() function and adds the ‘Expect:’ directive as is required to communicate with Twitter successfully.  We set the cURL options, make the call, hang up and return the result.  Now let’s put that into action.

$baseString = buildBaseString($baseURI, $oauth); //build the base string
 
$compositeKey = getCompositeKey($consumerSecret, null); //first request, no request token yet
$oauth_signature = base64_encode(hash_hmac('sha1', $baseString, $compositeKey, true)); //sign the base string
 
$oauth['oauth_signature'] = $oauth_signature; //add the signature to our oauth array
 
$response = sendRequest($oauth, $baseURI); //make the call

Now, if all went well your response should contain the “oauth_token” and the “oauth_token_secret”.  If not, you must have typed something wrong, keep trying until you get the token and secret handed back, or drop me a line and I’ll make sure I didn’t mistype something.

Now, take the “oauth_token” and the “oauth_token_secret” and store it.  We’re going to be using it to make a call to get our authorization url.

Constructing The Authorization URL

To construct the authorization URL, we’re going to be using the request token we received back from Twitter in the previous section Getting The Request Token, the “oauth_token”.  The authorization url has the following format:

http://api.twitter.com/oauth/authorize?oauth_token=$oauth_token

Where the $oauth_token variable is the actual value your received from Twitter parameterized as “oauth_token”.  Redirect the browser to this URL and it will prompt the user for their Twitter username/password if they’re not logged in, then it will ask permission to authorize use with your registered application.  You should see something similar to the following:

Twitter Connect Authorization

Once the user has authorized use, the browser will be redirect back to the “oauth_callback” parameter you specified earlier in your get request token call.  Here is where you will receive the user’s “screen_name”, “user_id”, “oauth_token” and “oauth_token_secret”.  Store these values and use them to make calls on behalf of the user to Twitter.  Hopefully this has helped you get over the initial shell shock and Twitter OAuth hurdle.  From this point forward, you’ll want to reference http://dev.twitter.com/pages/auth to find out more on making calls to Twitter resources on behalf of the user.

The source code for this example is available for download and use:

Download Project Files