I have written a very simple application to update my twitter status on a given condition. I have used the twitter documentation to understand the requirements of creating the OAuth signature and also how to structure the Authorization header. I then send the request with cURL in PHP.
Using the OAuth Tools on the twitter dev site, I compared both my signature base string and authorization header, and both are exactly the same:
Signature Base String
POST&https%3A%2F%2Fapi.twitter.com%2F1%2Fstatuses%2Fupdate.json&oauth_consumer_key%3DYNxxxxxxxxxxxWnfI6HA%26oauth_nonce%3D31077a3c7b7bee4e4c7e2b5185041c12%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1340729904%26oauth_token%3D2991771-4csoiO2fxmWgSxxxxxxxxxxDjWj2AbyxATtiuadNE%26oauth_version%3D1.0%26status%3Dblah%2520test%2520blah.
Authorization header
Authorization: OAuth oauth_consumer_key="YN4FLBxxxxxxxxxxI6HA", oauth_nonce="31077a3c7b7bee4e4c7e2b5185041c12", oauth_signature="M2cXepcxxxxxxxxxxAImeAjE%2FHc%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1340729904", oauth_token="2991771-4cxxxxxxxxxxSmRvjzMoooMDjWj2AbyxATtiuadNE", oauth_version="1.0"
Obviously I've replaced some characters with x
to hide my data, but comparing the two character for character yields exactly the same result. For reference, I hard-code the timestamp and nonce that the OAuth Tool generates so that my values can be the same for checking. My access level is set to Read and write. On that same page there is a final example - the command to run with cURL on the command line. When I run this command, it works perfectly and posts to my twitter feed with no issue.
With that in mind I believe everything I've created so far is fine, and don't think there's much point me posting the code that generates the details mentioned previously. However the code that I use to make the call, using cURL, I think is the culprit, but can't tell why:
<?php
// ...
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $baseUrl);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: $header"));
curl_setopt($curl, CURLOPT_POSTFIELDS, array('status' => $status));
$result = json_decode(curl_exec($curl));
curl_close($curl);
var_dump($result);
Note that $baseUrl
, $header
and $status
are the same variables used in generating the signature base string and authorization header, which matched just fine.
The output of the page when run is:
object(stdClass)#1 (2) { ["error"]=> string(34) "Could not authenticate with OAuth." ["request"]=> string(23) "/1/statuses/update.json" }
I hope there are enough details here for someone to point me in the right direction!
After much more searching, testing with apache_request_headers()
and sticking to the notion that my data was fine and it was cURL where the problem laid, I realised that cURL was setting the Content-type
of the request as multipart/form-data;
and adding boundary information, obviously with a longer Content-Length
field too. This meant that the status wasn't getting sent correct, I presume because of a malformed multipart/form-data;
request.
The solution was to send it as a string. For instance, this works:
curl_setopt($curl, CURLOPT_POSTFIELDS, 'status='. rawurlencode($status));
But I found that there's an even nicer way (especially with multiple values, when I want to use an array):
$postfields = array('status' => $status);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postfields));
which looks much nicer IMHO.
I think it's your nonce. From the docs: "The oauth_nonce parameter is a unique token your application should generate for each unique request" (emphasis mine).
Caveat: I'm more familiar with OAuth 2 + Java or JavaScript rather than OAuth 1 + PHP.
If that's not it (or not the only thing), you could compare your actual HTTP request (e.g. using WireShark) to the sample request they document on that page. The note there on "Building the header string" may help too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With