This tutorial is for programmers who are struggling with code that needs to interface directly with an OAuth flow. This is not a general introduction to OAuth.
The OAuth flow can seem byzantine with multiple steps that must be completed before you can make a signed API call.
Some OAuth write ups give example request and responses, while others includes almost fully functioning applications; neither work well when you need to debug why your own implementation of OAuth does not work.
This tutorial contains real code that prints actual OAuth requests and responses as plainly as possible.
I have broken down the Twitter OAuth 1.0a flow into individual, self-contained PHP scripts that can be run from the command line, from requesting a token to making a signed API call. See the Twitter sign-in documentation for reference.
My scripts are deliberately devoid of any web session interactions, database interactions, or even command line option handling, just to keep them as simple as possible. It’s straight, standalone procedural code, no objects. If you want to change something, just edit the code and run it.
The goal of the code is to be as transparent as possible, to show you exactly what is sent and what is received. If you look at the code in getreqtok.php, getacctok.php, and tweet.php, you can see that most of them can be combined easily into one function, but they are separated for clarity.
Output: consumer key and consumer secret.
This is self explanatory and requires no code. At the end of the process, you will have a consumer key and a consumer secret. Please keep the consumer secret secret; it is used to sign all of your requests to Twitter.
input: consumer key and secret
output: token and secret to use for Authentication or Authorization
Getting a “request token” is the first step on the road to making a signed API call. If a user has never granted your application permission to do something on his behalf, this is where you start.
Take a look at the getreqtok.php script. The get_request_token function is straight forward. You’ll find most of the supporting functions in either globals.php or oauth_helper.php.
Remember to set the OAUTH_CONSUMER_KEY and OAUTH_CONSUMER_SECRET in globals.php before running the script.
Since this is a command line script, just run it like this:
Change the $debug variable from 0 to 1 in globals.php. Rerun the script, and observe the raw request and header and response.
Flip the value of the $passOAuthInHeader boolean and see how things differ when OAuth credentials is passed via query parameters v.s. HTTP headers.
For the purposes of this tutorial, leave the $callback parameter as the string ‘oob’, allowing us PIN-based authentication.
A successful response to this step will contain a [request] token, a [request] token_secret. At the end of the script, it will print a URL to cut-and-paste into your browser. See Step 3, next.
input: URL from Step 2
There is no code here. For the purposes of this tutorial, cut-and-paste the url from the conclusion of step 2 into your browser.
At the conclusion of this step, your browser should display a short number, called an “oauth verifier”. Copy this value down and insert it into the getacctok.php script to be used in step 4.
input: consumer key and secret (step 1),
input: request_token and secret (step 2),
input: oauth_verifier (step 3)
output: access_token, access_token_secret, session_handle
You’re almost there. At the conclusion of step 4, you will receive an access token that allows you to call all the API end points of Twitter.
The script getacctok.php demonstrates how to perform this step. It is very similar to the getreqtok.php script from step 2. Only the inputs are different. Fill in the request token and request token secret from step 2, and the oauth verifier from step 3, and run the script.
In the script’s output, note the [access] oauth_token, [access] oauth_token_secret, user_id, and screen_name. The access token and secret will be used to sign API calls. Twitter does not expire this access token, so you will not have to go through a token refresh step.
Making an API call
input: post data
input: consumer key and secret (step 1)
input: access_token and secret (step 4)
output: response from api call
This is the step you have been working toward: actually making an API call to post a tweet. Once you have the access token and secret from Step 4, you can keep using them over and over again for your API calls.
This is the step where most people run into trouble, because it requires mingling parameters that are not OAuth related with those that are.
Look at the tweet.php script. It posts the string ‘Hello World!’ to your twitter status. Edit the script and enter the access token, access token secret, and any tweet you want to post.
Run it, and refresh your Twitter home page.
Congratulations you have posted a tweet!
Note that you should not post the exact same message more than once; Twitter will reject the second one as a duplicate.
The OAuth HMAC signture generation step that trips most people up is the generation of the Signature Base String, which requires some esoteric “normalization” operation. You can read about it from the spec directly.
A Signature Base String is a RFC 3986 encoded concatenation of:
- An uppercased HTTP method: GET, POST, etc.
- An ‘&’
- A url without any parameters (scheme://fqdn/path)
- An ‘&’
- All the query parameters (combined for both the API call and those for oauth) encoded according to rfc 3986 AND alpha-sorted by key. DO NOT include the oauth_signature parameter in this step, because you are generating the oauth_signature.
If you read that last paragraph carefully, you’ll note that the stuff in a signature base string is double rfc 3986 encoded.
A Signature Key is the concatenation of:
- rfc 3986 encoded consumer_secret
- rfc 3986 encoded token_secret
Then you apply the hmac-sha1 function using the signature_key to hash the signature_base_string and finally base64_encode the whole thing:
$sig = base64_encode(hash_hmac('sha1', $signature_base_string, $signature_key))
Odds and ends to keep in mind
- Note that the sorting and encoding of query parameters is done both when constructing the query parameter string, and when constructing the HMAC signature base string.
- When normalizing the signature base string, the ‘?’ separating the url from the parameters (if you’re using GET) is replaced with a ‘&’.
- If you are using POST instead of GET, make sure that the HTTP method string is POST when normalizing the signature base string.
- Make sure that you are using the token secret that goes with the correct token.
- If you get signature invalid error, check your Signature Base String normalization code. Be careful of the deliberate double encoding.
- When debugging, output what you are actually passing to and receiving from the server. Try capturing the actual data that is leaving your machine. If you are testing a web application in Firefox, for example, the Live HTTP Header plugin is great for this.