How can I access auth-only Twitter API methods from a web application
Asked Answered
L

2

6

I have a web application for iPhone, which will ultimately run within a PhoneGap application - but for now I'm running it in Safari.

The application needs to access tweets from Twitter friends, including private tweets. So I've implemented OAuth using the Scribe library. I successfully bounce users to Twitter, have them authenticate, then bounce back.

At this point the web app has oAuth credentials (key and token) which it persists locally. From here on I'd like it to user the Twitter statuses/user_timeline.json method to grab tweets for a particular user. I have the application using JSONP requests to do this with unprotected tweets successfully; when it accesses the timeline of a private Twitter feed, an HTTP basic authentication dialog appears in the app.

I believe that I need to provide the OAuth credentials to Twitter, so that my web application can identify and authenticate itself. Twitter recommends doing so through the addition of an HTTP Authorization header, but as I'm using JSONP for the request I don't think this is an option for me. Am I right in assuming this?

My options therefore appear to either be putting the oAuth credentials as query-string parameters (which Twitter recommends against, but documentation suggests still supports); or proxying all the Tweets through an intermediate server. I'd rather avoid the latter.

I access the Twitter API using URLs of the form

http://api.twitter.com/1/statuses/user_timeline.json?user_id=29191439&oauth_nonce=XXXXXXXXXXX&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1272323042&oauth_consumer_key=XXXXXXXXXX&oauth_signature=XXXXXXXXXX&oauth_version=1.0

When user_id is a public user, this works fine. When user_id is a private user, I get that HTTP Basic Auth dialog. Any idea what I'm doing wrong? I'm hoping it's something embarrassingly simple like "forgetting an important parameter"...

Lycopodium answered 20/1, 2011 at 20:24 Comment(0)
J
4

The oAuth stanza needs to be exact, as per http://dev.twitter.com/pages/auth#auth-request - I ended up building an Authorization: header that I could first check with curl.

I built it using the really helpful interactive request checker at http://hueniverse.com/2008/10/beginners-guide-to-oauth-part-iv-signing-requests/

Here's a friends API request for a protected user:

curl -v -H 'Authorization: OAuth realm="https://api.twitter.com/1/friends/ids.json", oauth_consumer_key="XXXXXXXXXXXXXXXX", oauth_token="XXXXXXXXXXXXXXXX", oauth_nonce="XXXXXXXXXXXXXXXX", oauth_timestamp="1300728665", oauth_signature_method="HMAC-SHA1", oauth_version="1.0", oauth_signature="XXXXXXXXXXXXXXXX%3D"' https://api.twitter.com/1/friends/ids.json?user_id=254723679

It's worth re-iterating that as you've tried to do, instead of setting the Authorization header via e.g. jquery's beforeSend function, that for cross-domain JSONP requests (which can't add HTTP headers) you can make oAuth requests by putting all the relevant key/value pairs in the GET request. This should hopefully help out various other questioners, e.g

  1. Set Headers with jQuery.ajax and JSONP?
  2. Modify HTTP Headers for a JSONP request
  3. Using only JQuery to update Twitter (OAuth)

Your request looks like it has a couple of problems; it's missing the user's oauth_token plus the oauth_signature doesn't look like it has been base64 encoded (because it's missing a hex encoded = or ==, %3 or %3D%3D respectively).

Here's my GET equivalent using oAuth encoded querystring params, which you can use in a cross-domain JSONP call:

https://api.twitter.com/1/friends/ids.json?user_id=254723679&realm=https://api.twitter.com/1/friends/ids.json&oauth_consumer_key=XXXXXXXXXXXXXXXX&oauth_token=XXXXXXXXXXXXXXXX&oauth_nonce=XXXXXXXXXXXXXXXX&oauth_timestamp=1300728665&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_signature=XXXXXXXXXXXXXXXX%3D
Jinn answered 21/3, 2011 at 22:49 Comment(1)
Very nice! Did this work out well for you and are you still using this method?Schlessinger
W
0

I was struggling with similar problem of making JSONP requests from Jquery, the above answer helped just to add what I did to achieve my solution.

I am doing server to server oauth and then I send oauth token, secret, consumer key and secret (this is temporary solution by the time we put a proxy to protect consumer secret). You can replace this to token acquiring code at client.

Oauth.js and Sha1.js download link! Once signature is generated.

Now there are 2 problems:

  1. JSONP header cannot be edited
  2. Signed arguments which needs to be sent as part of oauth have problem with callback=? (a regular way of using JSONP).

As above answer says 1 cannot be done. Also, callback=? won't work as the parameter list has to be signed and while sending the request to remote server Jquery replace callback=? to some name like callback=Jquery1232453234. So a named handler has to be used.

function my_twitter_resp_handler(data){
    console.log(JSON.stringify(data));
}

and getJSON did not work with named function handler, so I used

var accessor = {
                   consumerSecret: XXXXXXXXXXXXXXXXXXXXXX,
                   tokenSecret   : XXXXXXXXXXXXXXXXXXXXXX

                 };

  var message = {  action: "https://api.twitter.com/1/statuses/home_timeline.json",
                   method: "GET",
                   parameters: []
                };
  message.parameters.push(['realm', "https://api.twitter.com/1/statuses/home_timeline.json"]);
  message.parameters.push(['oauth_version', '1.0']);
  message.parameters.push(['oauth_signature_method', 'HMAC-SHA1']);
  message.parameters.push(['oauth_consumer_key', XXXXXXXXXXXXXXXX]);
  message.parameters.push(['oauth_token', XXXXXXXXXXXXXXX]);
  message.parameters.push(['callback', 'my_twitter_resp_handler']);

  OAuth.completeRequest(message, accessor);

  var parameterMap = OAuth.getParameterMap(message.parameters);

Create url with base url and key value pairs from parameterMap

jQuery.ajax({ 
               url: url, 
               dataType: "jsonp",
               type: "GET",
              });
Wise answered 30/1, 2012 at 17:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.