Translate

Image of Android Wireless Application Development
Image of RHCE Red Hat Certified Engineer Linux Study Guide (Exam RH302) (Certification Press)
Image of Beginning Google Maps API 3
Image of Operating System Concepts

Update Twitter Status using PHP and OAuth

Prior to Twitter requiring the use of OAuth to authenticate a user, it was possible to update your status on Twitter using PHP and your Twitter username and password credentials. Probably the most popular way to do this was to use Curl as shown in the following example:

<?php

$username = 'your_twitter_username';
$password = 'your_twitter_password';
$message = 'Using PHP and curl to update my status';
$url = 'http://twitter.com/statuses/update.xml';

$curl_handle = curl_init();
curl_setopt($curl_handle, CURLOPT_POST, 1);
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, "status=$message");
curl_setopt($curl_handle, CURLOPT_USERPWD, "$username:$password");
curl_setopt($curl_handle, CURLOPT_URL, "$url");
curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);

$status = curl_exec($curl_handle);
curl_close($curl_handle);
print_r($status);
?>


This method of authentication using a username and password credentials is called basic authentication by HTTP and Twitter. Since August 2010, however Twitter deprecated basic authentication and has required the use of OAuth 1.0 to authenticate applications that access Twitter using any of the Twitter APIs.

According to Twitter:

The move to OAuth will mean increased security and a better experience. Applications won’t store your username and password, and if you change your password, applications will continue to work.

OAuth’s stated objective is to specify an authorization delegation protocol in which one party (AKA the Consumer in Oauth terminology) can access another parties resources (AKA the Service Provider) on behalf of a third party (AKA the User). The Service Provider, i.e. Twitter in our particular case, controls all aspects of the Oauth implementation.

twitter oauth flow diagram

This use case is known as the 3-legged scenario and probably is the most common one. Another use case is the direct access scenario (AKA 2-legged scenario) where the Consumer is accessing resources on behalf of itself, i.e. the Consumer and the User are the same entity. This is the use case we will be discussing in the rest of this post. By the way, Twitter calls this the Out-Of-Band (oob) case.

The OAuth 1.0 protocol is detailed in RFC 5849. OAuth 1.0 defines three signatures methods for signing requests: PLAINTEXT, HMAC-SHA1 and RSA-SHA1. Twitter uses HMAC-SHA1.

Let us get started with the demonstration. I assume you are already familiar PHP, Twitter and dev.twitter.com and know how to register an application with Twitter. Ensure that you select “Read and Write” for the “Default Access type” and “Client” for the “Application type” when registering your application.

The following simple PHP script which we will call oauth.php demonstrates the Twitter 2-legged use case:

<?php

require_once('twitteroauth/twitteroauth.php');

define('OAUTH_CONSUMER_KEY', 'FPPng7ihYFrcabcDFE122Q');
define('OAUTH_CONSUMER_SECRET', 'XzVMv3X5mLAEcWs50A24waXtuPBVdgCTO1yapoM');

if ($_SERVER['argc'] == 0)
{
    echo "Usage: ".$_SERVER['argv'][0]." [register | validate <pin>] <br />";
    exit();
}

if (isset($_GET["register"]))
{
    // create a new TwitterOAuth object and request a token
    $oauth = new TwitterOAuth(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET);
    $request = $oauth->getRequestToken();

    // parse out the request tokens
    $request_token = $request["oauth_token"];
    $request_token_secret = $request["oauth_token_secret"];

    // and save them to file
    file_put_contents("request_token", $request_token);
    file_put_contents("request_token_secret", $request_token_secret);

    // Generate a request link and output it
    $request_link = $oauth->getAuthorizeURL($request);
     header('Location: ' . $request_url);
}
elseif (isset($_GET["validate"]))
{
    if (!isset($_GET["pin"]))
    {
        echo "A seven digit PIN is required <br />";
        exit();
    }
    $pin = $_GET["pin"];

    $request_token = file_get_contents("request_token");
    $request_token_secret = file_get_contents("request_token_secret");

    // create a new TwitterOAuth object. This time include request token and secret
    $oauth = new TwitterOAuth(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET, 
                                            $request_token, $request_token_secret);

    // using the 7 digit PIN, ask Twitter for an access token & secret
    $request = $oauth->getAccessToken(NULL, $pin);

    // parse the request
    $access_token = $request['oauth_token'];
    $access_token_secret = $request['oauth_token_secret'];

    // test access token and secret by calling verify credentials
    $oauth = new TwitterOAuth(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET,  
                                             $access_token, $access_token_secret);
    $userinfo = $oauth->get('account/verify_credentials');

    // and outputting some information about user
    echo "<br /><br />";
    echo "User ID: " . $userinfo->id . "<br />";
    echo "Screen Name: " . $userinfo->screen_name . "<br />";
    echo "Name: " . $userinfo->name . "<br />";

    // print_r($userinfo);

    // write OAuth configration file 
    $configFile = "configoauth.php";
    $fh = fopen($configFile, 'w') or die("Cannot open configoauth.php");
    fwrite($fh, "<?php\n");
    fwrite($fh, "define('OAUTH_CONSUMER_KEY', '" . OAUTH_CONSUMER_KEY . "');\n");
    fwrite($fh, "define('OAUTH_CONSUMER_SECRET', '" . OAUTH_CONSUMER_SECRET . "');\n");
    fwrite($fh, "define('OAUTH_ACCESS_TOKEN', '" . $access_token . "');\n");
    fwrite($fh, "define('OAUTH_ACCESS_TOKEN_SECRET', '" . $access_token_secret . "');\n");
    fclose($fh);

    echo "Created OAuth configuration file 'configoauth.php'. <br />";
}

exit();
?>


This script uses two files from Abraham Williams open source Twitter OAuth library, i.e. twitteroauth/twitteroauth.php and twitteroauth/OAuth.php. Since this library does not currently support the oob case using a PIN, it requires one modification to twitteroauth.php to replace the existing getAccessToken function with the following function:

function getAccessToken($token = NULL, $pin = NULL) {
   if($pin) {
      $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', array('oauth_verifier' => $pin));
   } else {
      $request = $this->oAuthRequest($this->accessTokenURL());
   }

   $token = OAuthUtil::parse_parameters($request);
   $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);

   return $token;
}


To use, invoke http://yoururl/oauth.php?register. After a few seconds Twitter should display a screen similar to the following:

twitter PIN display screen

Next, invoke http://yoururl/oauth.php?validate&pin=1234567 (obviously replace 1234567 with the 7 digit PIN assigned to you by Twitter and some information about your account will be displayed on the webpage together with a “Created OAuth configuration file ‘configoauth.php'” message.

Here is an overview of the flow for this use case:

  • Build A TwitterOauth object using your client (consumer) credentials
  • Request temporary credentials from Twitter
  • Build authorization URL for Twitter
  • Redirect user to authorization URL
  • Users logs into Twitter using their username and password and authorizes access
  • Twitter displays a 7 digit authorization PIN
  • Rebuild TwitterOauth object using client credentials and temporary credentials
  • Get access credentials from Twitter using 7 digit PIN
  • Rebuild TwitterOauth object using client credentials and access credentials
  • Access Twitter APIs

Now that you have all four tokens (2 consumer, 2 access), you do not need to go through the previous steps again. They are available to you in the configoauth.php file.

You can simplify use the four tokens to authenticate yourself to Twitter and update your Twitter status in a few lines of PHP code as shown below:

<?php

require_once('twitteroauth/twitteroauth.php');
require_once("configoauth.php");       

$message = 'Using PHP and Oauth to update my status';

$connection = new TwitterOAuth(OAUTH_CONSUMER_KEY,  OAUTH_CONSUMER_SECRET, 
                                                OAUTH_ACCESS_TOKEN, OAUTH_ACCESS_TOKEN_SECRET);
$parameters = array('status' => $message);
$status = $connection->post('statuses/update', $parameters);

// print_r($status);
?>


Easy once you have the correct credentials!

The problem with this approach is that it requires you to store all four tokens either in the PHP script or in a configuration file somewhere. No matter what approach you take, somewhere along the way you end up having to store some credentials. This implies the you must take care to ensure that configauth.php is not accessible to the outside world.

If the oauth.php script does not work for you, one thing to check is your system clock. Make sure your system clock is accurate otherwise a request token may not be issued by the Service Provider. It is known that authentication will sometimes fail if the system clock on the user’s system is skewed even slightly ahead or is skewed backwards. Sometimes Twitter’s authentication servers get overburdened and do not handle a request thus causing an authentication failure to occur. Twitter returns very generic 401 errors when this occurs and it can be difficult to figure out what is actually happening.

Enjoy!
 

1 comment to Update Twitter Status using PHP and OAuth

  • Wayne

    This seems to be exactly what I’m looking for. I just need to authorize a script that will be used to send automatic updates to my Twitter status, and OAuth has made that far more difficult than expected. I’ve carefully followed all the instructions above three times now and always end up in the same place: When I point my browser to the script, it just dies silently on a white page. No errors are emitted, and none are written to system logs. Interestingly, if I just run oauth.php from the command line, it simply exits in the same silence.

    Has Twitter changed things again, or might there be a way I could troubleshoot this?