Twitpic OAuth - I'm Stuck
Twitpic has implemented an OAuth API. No more having to hand out passwords to all and sundy. Only I'm too much of a dunderhead to get it working. Perhaps it's a combination of heatstroke or this rotten head-cold, but I just can't see what I'm doing wrong. Any help much appreciated.
The easy bit.
It's easy to post the data to Twitpic
$media_data = array( 'media' => '@'.$_FILES['media']['tmp_name'], 'message' => html_entity_decode($_POST['message']), 'key'=>'123465789132465' ); curl_setopt($ch,CURLOPT_POSTFIELDS,$media_data);
OAuth Credentials
Using Abrahams OAuth library for PHP, it's easy to get the required OAuth data.
require_once('OAuth.php'); // instantiating OAuth customer $consumer = new OAuthConsumer(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET); // instantiating signer $sha1_method = new OAuthSignatureMethod_HMAC_SHA1(); // user's token list($oauth_token, $oauth_token_secret) = explode('|', $GLOBALS['user']['password']); $token = new OAuthConsumer($oauth_token, $oauth_token_secret); // signing URL $fakeurl = 'https://twitter.com/account/verify_credentials.xml'; $request = OAuthRequest::from_consumer_and_token($consumer, $token, 'GET', $fakeurl, array()); $request->sign_request($sha1_method, $consumer, $token); $OAuthurl = $request->to_url();
The Tricky Bit
I'm following the header example in the API documentation. Passing these variable to Twitpic is where I seem to go wrong.
$header = array( 'X-Auth-Service-Provider: https://api.twitter.com/1/account/verify_credentials.json', 'X-Verify-Credentials-Authorization: OAuth realm="http://api.twitter.com/"' );
I then modify the second header so it reads
"X-Verify-Credentials-Authorization: OAuth realm="http://api.twitter.com/", oauth_consumer_key="aaaaaaa", oauth_nonce="bbbbbbbbbbb", oauth_signature="ccccccccccccc%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="123456798", oauth_token="15948715-dddddddddd", oauth_version="1.0""
The Error
401 "Could not authenticate you (header rejected by twitter)."
GAH!
Tom Parker says:
Hmm. The only immediately obvious item (yet probably unlikely as I think/hope PHP would whinge about this) is that your replacement headers have a quote inside them around the api.twitter.com bit which hasn't been escaped like the original one was. Also, according to their example, they all need to have their parameters in quotes.
The error you're getting is probably better translated to "our parser barfed, so let's assume you didn't give us everything we wanted and ergo panic". This is an insanely annoying and common problem when trying to build this sort of thing, and unfortunately there's a trade-off between nice error messages v.s. making it easier to find the flaws in stuff for dark-hat folks, and they tend to err on the paranoid side.
(Also, twitpic is being a bit odd with OAuth, as the spec recommends the use of HTTP POST variables for sending all this stuff...)
Terence Eden says:
Ah! Indeed you are wise. The correct code should be
$header = array('X-Auth-Service-Provider: https://api.twitter.com/1/account/verify_credentials.json', 'X-Verify-Credentials-Authorization: OAuth realm="http://api.twitter.com/"');
Now at least the error I get back is from Twitter!
rik says:
I'd be thinking the POST thing.
Terence Eden says:
Nah, the post works. If it didn't, Twitpic wouldn't forward the headers on to Twitter.
Terence Eden says:
I've updated the blogpost. Sending through the headers in what I think is the correct format. Now I get 401 “Could not authenticate you (header rejected by twitter).”
Stephen Corona says:
Hi Terence,
I believe the problem is that you are signing the OAuth request using verify_credentials.xml ($fakeurl = 'https://twitter.com/account/verify_credentials.xml). We need the request to be signed for https://api.twitter.com/1/account/verify_credentials.json. Try changing the value of $fakeurl and it should work.
Terence Eden says:
You beauty! Nice one. Can't believe I missed that.
All seems to work - the image appears on Twitpic, but not on Twitter. Is there a specific parameter I need to pass?
Thanks
T
Stephen Corona says:
Hi Terence,
Unfortunately, with the way OAuth Echo works, we can only access the URL that you sign for (in this case, https://api.twitter.com/1/account/verify_credentials.json). This means, that we are unable to post a tweet on your behalf to twitter, because the oauth header you are signing is not for statuses/update.
Twitter is working on a solution for us, but, for the time being, you'll have to post the tweet yourself. When you upload an image, the twitpic url is included in the JSON or XML response, so you can pull the URL from there to insert into your tweet.
Terence Eden says:
Perfect. Got it working. Thanks for all your help.
Bruno Barbieri says:
Forget my comment. Got it workin' too. Thank you anyway.
toshi says:
At last, Did you work well? if so, tell me more specific? i got 401 “Could not authenticate you (header rejected by twitter).” now.
could you paste some code on this board?
Terence Eden says:
Full details are at http://shkspr.mobi/blog/?p=2084
toshi says:
thank you very much! my mistake is OAuth libraries, that is kind of wrong. $schema was always designated 'http'. in function get_normalized_http_url(). changing it to Abraham’s OAuth libraries, getting things down!