How to sign an image upload request


#1

0
down vote
favorite
so my app can sign people in to twitter, can send tweets, and suck in followers etc.

However getting stumped with how to upload an image…

so far all my requests are to api.twitter.com

now i build my signature base string with the standard oath parameters

[parameterList addObject:[NSString stringWithFormat:@"%@=%@&",consumerKeyKey,consumerKeyValue]];

[parameterList addObject:[NSString stringWithFormat:@"%@=%@&",nonceKey,nonceValue]];

[parameterList addObject:[NSString stringWithFormat:@"%@=%@&",signatureMethod,signatureMethodValue]];

[parameterList addObject:[NSString stringWithFormat:@"%@=%@&",tokenKey,tokenKeyValue]];

[parameterList addObject:[NSString stringWithFormat:@"%@=%@&",timestampKey,timeStampValue]];

[parameterList addObject:[NSString stringWithFormat:@"%@=%@&",oauthVersionKey,oauthVersionValue]];
Then i construct the base string with the Http method, the url , and then the parameters above, url encode it and hash the lot. Never had any problems

However now i am trying to use upload.twitter.com/1.1/media/upload.json

i am passing a body parameter “media_data” which contains a base64 encoded image

so i tried first using the standard pattern (https method, url , oath parameter list) it failed (401)

then i read this somewhat ambiguous instruction here

https://dev.twitter.com/rest/public/uploading-media

Because the method uses multipart POST, OAuth is handled a little differently. POST or query string parameters are not used when calculating an OAuth signature basestring or signature. Only the oauth_* parameters are used.

so i don’t have query string parameters, so fine, and i can remove the HTTP method

what about the url? this isn’t mentioned anywhere??

suffice to say i tried with no method (so just url, parameters) got a 401

then tried removing the url so just parameters got a 401

does anyone know exactly what values need to go into the base string when calculating the auth header for upload.twitter.com/1.1/media/upload.json" ??


#2

I have the exact same issue as you! Yes, the instructions here:- https://dev.twitter.com/rest/public/uploading-media … i.e. :-

[quote]Because the method uses multipart POST, OAuth is
handled a little differently. POST or query string parameters are not
used when calculating an OAuth signature basestring or signature. Only
the oauth_* parameters are used. [/quote]

…are annoyingly vague.

I keep getting this error:-

They could answer the solution succinctly by simply posting ad-verbatim a Request example. All I see is a Response example at the bottom of the page (https://dev.twitter.com/rest/public/uploading-media).

I have no idea how to authenticate a media/upload call because I can’t use querystring or POST to do it…?!


#3

Further to my previous reply, here’s my authentication header:-

oauth_consumer_key=“xxx”, oauth_nonce=“xxx”, oauth_signature=“xxx”, oauth_signature_method=“HMAC-SHA1”, oauth_timestamp=“1426684077”, oauth_token=“xxx”, oauth_version=“1.0”

This looks perfect to me - obviously “xxx” replaces actual codes. Yet I get :-

{“errors”:[{“code”:32,“message”:“Could not authenticate you.”}]}


#4

I am running in to this same issue. Twitter’s documentation for chunked media upload still has the same vague language as it did when this issue was originally posted 9 months ago. Has anyone found the solution?


#5

Answering my own question… the solution here is that the OAuth signature for this case is based on the following:

  • The request URL
  • The HTTP request method
  • The query string parameters from the HTTP request line
  • The oauth_* parameters

No other values are used in the calculation of the OAuth “signature base string” when the content-type of a POST request is anything besides application/x-www-form-urlencoded. Refer to Section 9 of the OAuth 1.0a specification.


#6

It actually seems deliberate that Twitter have written their API docs to be as obscure as possible in the hopes that more people go off and use the off-the-shelf frameworks. Why create an API then if they can’t make it helpful?

I’m also doing custom code and find it shocking they blatantly left out the sample request for uploading an image which would save a lot of people some major time wasting.

Anyway, it turns out to be far simpler than their docs suggest (the signature that is). Creating the actual image post data is not even covered by their docs, it seems to be assumed you know everything already. It took me some time to figure out how that worked based on the generic way to CURL images with base64 encoded images.

For the signature, you basically do nothing different than the statuses/update, just leave out any query key value pairs that form the specific parameters for an image upload. e.g media_data, media etc. Here is some of my PHP code, you can probably figure out what the functions do from the comments.

$authorisation['oauth_consumer_key'] = TWT_CONSUMER_KEY;
$authorisation['oauth_nonce'] = base64_encode(md5(generateRandomCode(10,fetchCodeString(5))));
$authorisation['oauth_signature_method'] = 'HMAC-SHA1';
$authorisation['oauth_timestamp'] = strtotime(date('Y-m-d H:i:s'));
$authorisation['oauth_token'] = TWT_ACCESS_TOKEN;
$authorisation['oauth_version'] = '1.0';
/**
 * GENERATE SIGNING KEY WITH RAWURLENCODE
 */
$signing_key = setOauthSigningKey(TWT_CONSUMER_SECRET, TWT_ACCESS_TOKEN_SECRET);
		
/**
 * AUTHORISATION PARAMETERS ARE PAIRED USING RAWURLENCODE
 */
$parameters = setOauthParameters($authorisation);

/**
 * CREATE BASE STRING INCLUDING METHOD, PARAMETERS AND REQUEST URL
* USING RAWURLENCODE
 */
$signature_base_string = setOauthBaseString('POST', $parameters, TWT_MEDIA_BASE_URL.TWT_IMAGE_UPLOAD);

/**
 * CREATE OAUTH SIGNATURE WITH HASH_HMAC/BASE64_ENCODE
 */
$authorisation['oauth_signature'] = setOauthSignature($signature_base_string,$signing_key); 
	
/**
* SORT ARRAY ALPHABETICALLY AS WE JUST ADDED THE SIGNATURE
 */
ksort($authorisation);
	
/**
* SET HEADER DATA FROM JUST THE OAUTH PARAMETERS
*/
$header = setOauthHeader($authorisation);

/**
* GET IMAGE DATA E.G FROM A DATABASE
*/
$the_images = array(
'image1' => 'image5.jpg',
'image2' => 'imaGe7.jpg',
'image3' => 'image6.jpg',
'image4' => 'image8.jpg'
);

/**
* UPLOAD IMAGES FILES AND RETURN THEIR MEDIA IDS READY TO CREATE A TWEET.
* POST DATA IS ALSO GENERATED BY THIS FUNCTION
*/
$the_media_ids = sendOauthImages($the_images, $header);

For me the following basically works perfectly, however your error was more likely due to the post data being invalid. Their API returns can’t authenticate if any part of the request is wrong, they don’t seem to provide any useful error codes that relate to the parts of the data sent e.g post data. Then again, maybe Oauth is just meant to be deeply obscure. Hope this helps someone.


#11