I'm trying to post a tweet but for any reason it doesn't work as expected.
I suspect that the issue could be related to the signature
string, but following what twitter says according to signing requests looks ok.
Here is my code:
function postTweet(user_id, AccessToken, AccessTokenSecret) { var base_url = 'https://api.twitter.com/1.1/statuses/update.json', oauth_nonce = randomString(), oauth_signature, oauth_timestamp = Math.floor(new Date().getTime() / 1000), reqArray, req, signature_base_string, signing_key; reqArray = [ "include_entities=true", 'oauth_consumer_key="' + CONFIG.TWITTER_CONSUMER_KEY + '"', 'oauth_nonce="' + oauth_nonce + '"', 'oauth_signature_method="HMAC-SHA1"', 'oauth_timestamp="' + oauth_timestamp + '"', 'oauth_token="' + AccessToken + '"', 'oauth_version="1.0"', 'status=' + encodeURIComponent("hello world") ]; req = reqArray.sort().join('&'); signature_base_string = "POST&" + encodeURIComponent(base_url) + "&" + encodeURIComponent(req); signing_key = CONFIG.TWITTER_CONSUMER_KEY_SECRET + '&' + AccessTokenSecret; oauth_signature = encodeURIComponent(CryptoJS.HmacSHA1(signature_base_string, signing_key).toString(CryptoJS.enc.Base64)); return $http.post('https://api.twitter.com/1.1/statuses/update.json', { status: 'hello world' }).then(function (response) { return response; }).catch(function (error) { console.log(error); }); }
As a response, I get that:
UPDATE
considering that in my project I already have $cordovaOauthUtility
I started using it this way:
function postTweet(accessToken, accessTokenSecret) { var params, signature; params = { include_entities: true, oauth_consumer_key: CONFIG.TWITTER_CONSUMER_KEY, oauth_nonce: $cordovaOauthUtility.createNonce(10), oauth_signature_method: "HMAC-SHA1", oauth_token: accessToken, oauth_timestamp: Math.round((new Date()).getTime() / 1000.0), oauth_version: "1.0" }; signature = $cordovaOauthUtility.createSignature('POST', 'https://api.twitter.com/1.1/statuses/update.json', params, { status: "hello" }, CONFIG.TWITTER_CONSUMER_KEY_SECRET, accessTokenSecret); return $http.post('https://api.twitter.com/1.1/statuses/update.json', { status: "hello" }, { headers: { Authorization: signature.authorization_header } }) .then(function (response) { return response; }).catch(function (error) { console.log(error); }); }
UPDATE 2
After trying all the posibilities, the problem persist. Here I paste a plnkr where I have my code.
3 Answers
Answers 1
You are using crypto's HmacSHA256
but sending HMAC-SHA1
as the oauth_signature_method
parameter which is the twitter one.
You should probably change your code to
oauth_signature = CryptoJS.HmacSHA1(signature_base_string, signing_key).toString(CryptoJS.enc.Base64);
If you look at your authorization
header, you can also notice that something is wrong with it. Indeed, you can see that the oauth_nonce
and the oauth_version
are prefixed by a &
sign, which shouldn't be the case and most likely mean to the api you are not specifying them. It probably comes from the fact you are using the same reqArray
to construct both the signature and the header, or your code is not updated.
You also probably don't want to change the global headers sent from your app, in case another request is sent to another api at the same time. Rather, you should send this authorization
header only for this specific xhr.
return $http.post('https://api.twitter.com/1.1/statuses/update.json', { status: 'hello world', }, { headers: { Authorization: auth, }, })
Answers 2
Well, you're clearly adding oauth_token
in your request array but it didn't show up in the screenshot? Is the AccessToken in the params undefined?
EDIT
According to the documentation, we must append double quotes to the headers. Try this?
reqArray = [ "include_entities=true", 'oauth_consumer_key="'+CONFIG.TWITTER_CONSUMER_KEY+'"', 'oauth_nonce="'+oauth_nonce+'"', 'oauth_signature_method="HMAC-SHA1"', 'oauth_timestamp="'+oauth_timestamp+'"', 'oauth_token="'+AccessToken+'"', 'oauth_version="1.0"', 'status='+encodeURIComponent("hello world") ];
Answers 3
Yikes.
I've downloaded your plnkr bundle and added a read only application key set. I only had to set up and make one change to get a {"request":"\/1.1\/statuses\/update.json","error":"Read-only application cannot POST."}
response. Initially I was receiving {"errors":[{"code":32,"message":"Could not authenticate you."}]}
.
Remove status: "hello"
from between the curly brackets { }
where you create your signature.
signature = $cordovaOauthUtility.createSignature('POST', 'https://api.twitter.com/1.1/statuses/update.json', params, { }, twitter.consumer_secret, twitter.access_token_secret);
My request headers become the following:
:authority:api.twitter.com :method:POST :path:/1.1/statuses/update.json :scheme:https accept:application/json, text/plain, */* accept-encoding:gzip, deflate, br accept-language:en-US,en;q=0.8 authorization:OAuth oauth_consumer_key="x",oauth_nonce="QFMmqiasFs",oauth_signature_method="HMAC-SHA1",oauth_token="y",oauth_timestamp="1496340853",oauth_version="1.0",oauth_signature="7Ts91LKcP%2FrYsLcF5WtryCvZQFU%3D" content-length:18 content-type:application/json;charset=UTF-8 origin:http://localhost referer:http://localhost/twits/ user-agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36
Googling eventually led me to a tutorial: Displaying the Twitter Feed within Your Ionic App. I noted his general createTwitterSignature
function does not take parameters and tweaked your code similarly.
function createTwitterSignature(method, url) { var token = angular.fromJson(getStoredToken()); var oauthObject = { oauth_consumer_key: clientId, oauth_nonce: $cordovaOauthUtility.createNonce(10), oauth_signature_method: "HMAC-SHA1", oauth_token: token.oauth_token, oauth_timestamp: Math.round((new Date()).getTime() / 1000.0), oauth_version: "1.0" }; var signatureObj = $cordovaOauthUtility.createSignature(method, url, oauthObject, {}, clientSecret, token.oauth_token_secret); $http.defaults.headers.common.Authorization = signatureObj.authorization_header; }
I've read conflicting things about why there should/shouldn't be other parameters there, but I believe the signature is just supposed to be the basis of access and doesn't hash in every operation you want to perform - see Understanding Request Signing For Oauth 1.0a Providers.
0 comments:
Post a Comment