I can't get user data from Twitter (Oauth NG-Cordova) (Twitter timeline and Facebook profile works) [SOLVED]

Hi all,

I’m implementing a login system using OAuth plugin. I have installed the last version from the nraboy repo. The issue occurs when i try to get the user data from the Twitter API. Here is my function:

getTwitterProfile: function() {

      var deferred = $q.defer();
      var token = angular.fromJson(getStoredToken());

      createTwitterSignature('GET', 
         'https://api.twitter.com/1.1/users/show.json');

      $http.get("https://api.twitter.com/1.1/users/show.json", { 
          params: { 
              screen_name: token.screen_name 
          }
      }).success(function(result) {
             alert('USER FROM TWITTER: '+result);
             deferred.resolve(result);
      }).error(function(error) {
             alert("Error: "+JSON.stringify(error));
             deferred.reject(false);
      });
      return deferred.promise;
    }

My token it’s OK, because if i change the url by the following on the get request for , it works:

    // Get user Timeline
    getTwitterProfile: function() {

      var deferred = $q.defer();
      var token = angular.fromJson(getStoredToken());

      createTwitterSignature('GET', 
          'https://api.twitter.com/1.1/statuses/home_timeline.json');

      $http.get("https://api.twitter.com/1.1/statuses/home_timeline.json")
           .success(function(result) {
                 alert('USER TIMELINE: '+result);
                 deferred.resolve(result);
      }).error( function(error) {
                alert("Error: "+JSON.stringify(error));
                deferred.reject(false);
      });
      return deferred.promise;
    }

The only difference is the URL and the params that i passed to request the user by name, following the Twitter API Docs: https://dev.twitter.com/rest/reference/get/users/show

The error msg is: Could not authenticate you.

But if i change the url, the Twitter API authenticates me so is not my token.

My createTwitterSignature function:

function createTwitterSignature(method, url) {
    var token = angular.fromJson(getStoredToken());
    var oauthObject = {
        oauth_consumer_key: clientId,
        oauth_nonce: $cordovaOauthUtility.createNonce(32),
        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 do the same with Facebook and it works like a charm:

// Get facebook profile
    getFacebookProfile: function() {
      var deferred = $q.defer();
      var token = JSON.parse(getStoredToken());

      $http.get("https://graph.facebook.com/v2.2/me", { 
          params: {
                  access_token: token, 
                  fields: "id,name,gender,location,website,picture,relationship_status",
                  format: "json"
           }
      })
     .success(function(result) {
           deferred.resolve(result);
      })
     .error( function(error) {
            alert("Error: "+error);
            deferred.reject(false);
      });
      return deferred.promise;
    }

Any ideas? maybe is my http request that is wrong?

I appreciate your help!

Thanks!

Hi @ivanbtrujillo,

I’m a little confused on what you’re doing, but I’ll just base this off the little red flags that I see.

  1. When signing requests for Twitter, you need to include all parameters used in your GET and POST requests in the signature. The users/show endpoint has two required parameters, user_id and screen_name so they must be included in the $cordovaOauthUtility.createSignature method. Instead I see you using an empty object {}

Start there and circle back.

If you need more help with the Oauth 1.0a protocol, maybe see this:

Regards,

Thanks Nick!

What I try to do is log users via OAuth with Twitter / Facebook and retrieve profile information (name and picture).

On Facebook it is quite simple, but Twitter have this problem. I get the username when receiving the Token, but to get the image need to make a GET request with parameters which do not work for me.

I didn’t know that i have to include the parameters on the signature.

This afternoon I’ll change the code and I’ll tell you something. Thank you very much for the support!

Yep, Oauth 1.0a is painful.

Let me know how it goes!

Hey @nickraboy It works like a charm. That was the problem, i just add the params on the $cordovaOauthUtility.createSignature method. Also, i added the params on the $http request. Here is the code, maybe will usefull for someone (i don’t see any full example of a GET request to Twitter API with parameters with ng-cordova Oauth).

//Create the Signature
function createTwitterSignature(method, url) {
    var token = angular.fromJson(getStoredToken());
    var oauthObject = {
        oauth_consumer_key: clientId,
        oauth_nonce: $cordovaOauthUtility.createNonce(32),
        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,{screen_name:token.screen_name}, clientSecret, 
        token.oauth_token_secret);

    $http.defaults.headers.common.Authorization =
         signatureObj.authorization_header;
}

Note that now indicates the screen_name: token.screen_name ; The token.screen_name value is ivanbtrujillo

On the request to the API, i’ve added the parameters (screen_name: token.screen_name) on the request too:

 // Get user profile from Twitter API
    getTwitterProfile: function() {

      var deferred = $q.defer();
      var token = angular.fromJson(getStoredToken());

      createTwitterSignature('GET',
             'https://api.twitter.com/1.1/users/show.json');

      $http.get("https://api.twitter.com/1.1/users/show.json",
               {params: { screen_name: token.screen_name}})
      .success(function(result) {
                deferred.resolve(result);
      })
     .error(function(error) {
                alert("There was a problem getting your profile");
                deferred.reject(false);
      });
      return deferred.promise;
    },

And it’s done!

Thanks for you support, you’re awesome nick, a few days ago you changed ng-oauth to resolve the problem with twitter error code 32 (here: https://github.com/nraboy/ng-cordova-oauth/issues/45) and now helps me with my problem.

2 Likes

No problem! Reach out any time you need some help :slight_smile:

Hi ivan,
Thank you very much for your post. It worked for me
Thanks a lot man

Regards
Anil Kumar

Thanks for this post. It helped me solve some problems I was having. I did not know you needed to pass the parameters inside the object on the createSignature method! Also didnt know you needed to specify the parameters on the $http.get request… I thought the params could be only on the requested url… Thanks nic and ivan! Very useful post for those trying to understand oauth 1a.

I decided to create a AngularJS wrapper library for the Twitter REST Api called ngTwitter. The process of grabbing data with those signed request is a a pain in the ass for a lot of people, so I hope this library can act as a little helper for people coming here looking for Ionic+Twitter integration.

You just need to have your Twitter App data and a valid OAuth token, then you can configure the library like this:

$twitterApi.configure(clientId, clientSecret, oauthToken);

Afterwards you can grab your user_timeline like this:

$twitterApi.getHomeTimeline({count: 5})

For more information check out the according tutorial How To Easily Use The Twitter REST Api With AngularJS

Thanks saimon, the wrapper helped me lot for twitter signature process to call api created by you, its really awesome thank you again for your efforts

Hello,
i’m having issues when uploading image using POST API, this is the situation i got:
in particular i’m posting an image with media_id on body request.
I checked the code of the library, and what I understood is that even when make a POST call this part of code adds to url request the params (optional data):
if (parameters !== {}) url = url + ‘?’ + $twitterHelpers.transformRequest(parameters);
This solution is ok when url characters does not exceed the maximum numbers of characters on a HTTP call, but when media_id is too long the call fails.
Could anybody can confirm this?
This is the code i’m using but without success:
var oauthObject = {
oauth_consumer_key: clientId,
oauth_nonce: $cordovaOauthUtility.createNonce(32),
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(“POST”, url,
oauthObject, {screen_name: token.screen_name}, clientSecret,
token.oauth_token_secret);
$http.defaults.headers.common.Authorization = signatureObj.authorization_header;
console.log(JSON.stringify(signatureObj));
var _headers = {
‘Authorization’: signatureObj.authorization_header,
‘Content-Type’: ‘application/x-www-form-urlencoded’
};
$http({
method: “post”,
url: “https://upload.twitter.com/…”,
data: JSON.stringify(base64String)
}).success(function(data, status, headers, config) {
console.log(data);
deferred.resolve(data);
})
.error(function(data, status, headers, config) {
console.log(data);
deferred.reject(status);
});
I have tested using both endpoint:
https://upload.twitter.com/
https://api.twitter.com/1.1… (deprecated)
This is the result i got:
Request URL:https://upload.twitter.com/
Request Method:POST
Status Code:401 Authorization Required
Request Headers
POST https://upload.twitter.com/… HTTP/1.1
Accept: application/json, text/plain, /
Origin: file://
User-Agent: Mozilla/5.0 (Linux; Android 4.4.2; LG-V500 Build/KOT49I.V50020f) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36
Authorization: OAuth oauth_consumer_key=“TG*********”,oauth_nonce=“yyBpmX9yienaHw0xe0izomB3Fp4zCQA0”,oauth_signature_method=“HMAC-SHA1”,oauth_token=“191362************”,oauth_timestamp=“1503497329”,oauth_version=“1.0”,oauth_signature="M8cv3Att*********"
Content-Type: application/json;charset=UTF-8
Request Payload
{,…}
media_data: "iv0 + long base64 string"
Response Headers
content-encoding:gzip
content-length:89
content-type:application/json; charset=utf-8
date:Wed, 23 Aug 2017 14:08:47 GMT
server:tsa_f
strict-transport-security:max-age=631138519
vary:Origin
x-connection-hash:c8db7d4f36b7340e16d86e5930b43a6a
x-content-type-options:nosniff
x-frame-options:SAMEORIGIN
x-response-time:126
x-tsa-request-body-time:1
x-xss-protection:1; mode=block

Thank you in advance.