Understanding OAuth – Tweeting from Scratch, Part 1
A common complaint about OAuth is that it is very difficult to understand, but perhaps some of that confusion is because of an expectation that the abstraction provided by a third-party library will erase the need to understand the steps of an OAuth transaction – it does not. This two-part article demonstrates how how OAuth v1 works by explaining the process of connecting a PHP application to the Twitter API using only a few built-in functions to post a message to a user’s Twitter stream.
The example code provided in this article is intended for educational purposes only. It lacks much practical use and error handling, Any real development should take advantage of an existing OAuth library, but after reading this article you’ll have a better understanding of how OAuth works and will be better equipped to troubleshoot any problems that may arise.
Obtaining Consumer Credentials
Posting to Twitter on behalf of a user without asking for a username and password combination every time requires a sort of “valet key”… this key is OAuth. In OAuth terms, your client application is called the consumer, the user is called the resource owner, and Twitter is the server or service provider.
Before Twitter will accept a post from your application, you need to obtain your own client credentials: the Consumer Key and Consumer Secret. Twitter, like most services that provide a public API, will grant you a key and secret after completing a registration form (available at dev.twitter.com/apps). With Twitter, you need to supply some information that will identify your application to the user during the authorization process, specifically its name, description, and website URL. You also need to enter a Callback URL, which I’ll explain later.
Once you have submitted the Create an Application form, you will be taken to a Details page for your new application. Scroll down to find your Consumer Key and Secret. You’ll need these along with the handful of endpoint URLs that are listed. Notice the application is granted Read Only access by default; since it will be posting tweets, you need to click the Settings tab and change the access to “Read and Write”.
Authorizing the Application
The Consumer Key and Consumer Secret allow your application to talk to the Twitter API, but those alone won’t let it post tweets on another user’s behalf. You need access credentials: an Access Token and Access Secret. To obtain these through a request to the Service Provider (Twitter) in a short conversation using the consumer credentials involving Twitter and the end-user. Obtaining the access credentials can be fairly painful, but luckily you only need to do this once per user. You can save the credentials indefinitely for later use and not require the user to reauthorize your application. The conversation requesting the access credentials requires its own set of credentials: the Request Token and Request Secret.
Authorization Step 1: Request Credentials
The authorization process typically starts by directing the user to an Authorize Twitter page. This is a page you create that initiates the request for a Request Token from Twitter and begins the OAuth authorization process. It must generate a URL used to grab the Request Credentials, and once you have the credentials you can redirect the user to Twitter to grant the application permission to post.
Requesting the Request Credentials requires a signed request, which means you need to send an OAuth signature along with other important parameters in the request. The signature is a base64-encoded hashed list of the request parameters. In Twitter’s case, the hashing algorithm is HMAC-SHA1. The signing process prevents anyone else from posing as your application with your credentials even though the Consumer Key is transmitted in plain text. The signature can only be reproduced by you (the Consumer) and the server (Twitter) because you two are the only entities that should know the Consumer Secret that hashes the signature.
Lets build a string the signature is based on:
<?php $requestTokenUrl = "http://api.twitter.com/oauth/request_token"; $authorizeUrl = "http://api.twitter.com/oauth/authorize"; $oauthTimestamp = time(); $nonce = md5(mt_rand()); $oauthSignatureMethod = "HMAC-SHA1"; $oauthVersion = "1.0"; $sigBase = "GET&" . rawurlencode($requestTokenUrl) . "&" . rawurlencode("oauth_consumer_key=" . rawurlencode($consumerKey) . "&oauth_nonce=" . rawurlencode($nonce) . "&oauth_signature_method=" . rawurlencode($oauthSignatureMethod) . "&oauth_timestamp=" . $oauthTimestamp . "&oauth_version=" . $oauthVersion);
Some of the above variables may be fairly obvious –
$requestTokenUrl was obtained from Twitter when you were granted consumer credentials, and
$oauthTimestamp is the current UNIX epoch time. The less obvious item is
$nonce, which is nothing more than a random string used only once (a difference nonce is used for each transaction). Typically an MD5-hashed random number works fine as a nonce. There is also
$oauthSignatureMethod which is always HMAC-SHA1 for Twitter, and the
$oauthVersion which is currently v1.0 for Twitter.
Next, the string for the signature is constructed as
$sigBase. OAuth says that the signature base must be the HTTP method (
GET in this case) followed by an “&”, followed by the URL-encoded request URL (
$requestTokenUrl) followed by another “&”, and finally a URL-encoded and alphabetized list of parameter key/value pairs (the values of which must also be encoded) separated by “&”s. Note that when OAuth wants something URL-encoded, it means RFC-3986. PHP’s
rawurlencode() function works because it encodes spaces as “%20” instead of “+” as
You also need a Signing Key. The key is always the Consumer Secret followed by an “&” and either 1) the OAuth Token Secret (which is part of the Token Credentials you don’t have yet), or 2) nothing. Then you can generate the final signature using PHP’s built-in
<?php $sigKey = $consumerSecret . "&"; $oauthSig = base64_encode(hash_hmac("sha1", $sigBase, $sigKey, true));
You put all the pieces together to construct a URL to request the Request Credentials:
<?php $requestUrl = $requestTokenUrl . "?" . "oauth_consumer_key=" . rawurlencode($consumerKey) . "&oauth_nonce=" . rawurlencode($nonce) . "&oauth_signature_method=" . rawurlencode($oauthSignatureMethod) . "&oauth_timestamp=" . rawurlencode($oauthTimestamp) . "&oauth_version=" . rawurlencode($oauthVersion) . "&oauth_signature=" . rawurlencode($oauthSig); $response = file_get_contents($requestUrl);
You’ll want a lot more error handling for anything beyond this simple demonstration, but for now I assume nothing will ever go wrong and you are able to receive the temporary Request Credentials in
The response sent back from Twitter looks like this:
oauth_token_secret values are extracted from the response and are used to construct the next link the user goes to for the second step in the authorization process. It’s a good idea to store the Request Credentials in the user’s session so they are available when the user returns from Twitter’s authorization page. The Authorization URL is provided on the Details page after registering your application with Twitter.
<?php parse_str($response, $values); $_SESSION["requestToken"] = $values["oauth_token"]; $_SESSION["requestTokenSecret"] = $values["oauth_token_secret"]; $redirectUrl = $authorizeUrl . "?oauth_token=" . $_SESSION["requestToken"]; header("Location: " . $redirectUrl);
Now that the application can send users to Twitter for authorization, it is a good time to add a Callback URL so Twitter can send them back to the application! The Callback URL is simply an address that Twitter will direct the user to after he has authorized your application to send tweets on his behalf, and is specified on the Detail page’s Settings tab.
When Twitter redirects the user to the Callback URL, it appends two additional parameters: your
oauth_token from the initial request which can be used for verification, and
oauth_verifier which is used in obtaining the Authorization Credentials.
Of the three sets of credentials needed to post tweets, you now have two – the Consumer Credentials and the Request Credentials. Next up: Access Credentials!
Authorization Step 2: Access Credentials
To obtain the Access Credentials you need the
oauth_token_secret, and the newly obtained
oauth_verifier. This step requires another signed request, this time to the Access Token URL displayed on the Details page.
<?php $oauthVersion = "1.0"; $oauthSignatureMethod = "HMAC-SHA1"; $accessTokenUrl = "http://api.twitter.com/oauth/access_token"; $nonce = md5(mt_rand()); $oauthTimestamp = time(); $oauthVerifier = $_GET["oauth_verifier"];
$accessTokenUrl is the next endpoint obtained from the Details page. A new
$nonce are generated, and
$oauthVerifier is sent back from the Twitter Authorization page. Not listed, but in the
$_SESSION array, are the request credentials from the previous step that are also required.
This step of the authorization process requires another signed request. Once the signature is built, it is used with the request for Access Credentials.
<?php $sigBase = "GET&" . rawurlencode($accessTokenUrl) . "&" . rawurlencode("oauth_consumer_key=" . rawurlencode($consumerKey) . "&oauth_nonce=" . rawurlencode($nonce) . "&oauth_signature_method=" . rawurlencode($oauthSignatureMethod) . "&oauth_timestamp=" . rawurlencode($oauthTimestamp) . "&oauth_token=" . rawurlencode($_SESSION["requestToken"]) . "&oauth_verifier=" . rawurlencode($oauthVerifier) . "&oauth_version=" . rawurlencode($oauthVersion)); $sigKey = $consumerSecret . "&"; $oauthSig = base64_encode(hash_hmac("sha1", $sigBase, $sigKey, true)); $requestUrl = $accessTokenUrl . "?" . "oauth_consumer_key=" . rawurlencode($consumerKey) . "&oauth_nonce=" . rawurlencode($nonce) . "&oauth_signature_method=" . rawurlencode($oauthSignatureMethod) . "&oauth_timestamp=" . rawurlencode($oauthTimestamp) . "&oauth_token=" . rawurlencode($_SESSION["requestToken"]) . "&oauth_verifier=" . rawurlencode($oauthVerifier) . "&oauth_version=". rawurlencode($oauthVersion) . "&oauth_signature=" . rawurlencode($oauthSig); $response = file_get_contents($requestUrl);
$response has the very useful
user_id and the much awaited Access Credentials!
This concludes the authorization part of this article. So far you’ve learned how to create a new Twitter application and use the provided consumer credentials to step through the OAuth “dance” to obtain the access credentials. In the second and final part of this series I’ll discuss using the access credentials to post a tweet to the user’s Twitter stream.