Android – OAuth updates to Twitter – Mea Cup O' Jo
Skip to content


Android – OAuth updates to Twitter

In the spirit of community giving here’s step by step tutorial on how to do OAuth Twitter status updates on Android

Prerequisites

I’m using most excellent oauth-signpost library for this tutorial. You will need both core and commonshttp4 jars which you should simply drop into your project/assets folder and add to your Eclipse’s build path

Register App

Go and register your new wonderful app on Twitter. When filling the form don’t forget to choose “browser” as “Application Type”. If you fail to do that or if your current app doesn’t have that option selected then you won’t be able to redirect back to your Android app after Twitter authorization step. The form asks for “Callback URL”, you can enter any valid URL doesn’t matter which one since you will provide the “real” one programmatically.
Note “Consumer key” and “Consumer secret” values – you will need these in your app

Common code

Create consumer and provider where you see fit so you can reuse these later

    CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(
            CONSUMER_KEY, CONSUMER_SECRET, SignatureMethod.HMAC_SHA1);

    OAuthProvider provider = new DefaultOAuthProvider(consumer,
            "http://twitter.com/oauth/request_token", "http://twitter.com/oauth/access_token",
            "http://twitter.com/oauth/authorize");
    HttpClient client = new DefaultHttpClient();

Authorization

Create some sort of trigger in your Android app such as checkbox “Enable Twitter”. When user triggers it the following should happen in your code

// Context ctx whichever way you passing it in
String authUrl = provider.retrieveRequestToken(CALLBACK_URL);
ctx.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));

Now – the CALLBACK_URL would be something like yourapp://twitt and basically it will be loaded by external browser if authentication/authorization is successful
So what will happen when this code is executed? The external browser will come up and display Twitter’s “Authorize Application Access” page. When user logs in and clicks “Allow” you should see message telling you that permission is granted and you will be redirected back.

Back from authorization

For your app to pick that app here are next steps
Add intent filter
Open AndroidManifest.xml and add the following lines to the activity that you want to handle further processing







Note “data” element – scheme and host should match your callback URL (remember yourapp://twitt?)
In Android when browser calls that callback URL then your app is brought forward and activity’s onResume() method is called. So in that method you should place the following code that basically gets you token and token_secret

// this must be places in activity#onResume()
Uri uri = this.getIntent().getData();
if (uri != null && uri.toString().startsWith(CALLBACK_URL)) {
    String verifier = uri.getQueryParameter(OAUTH_VERIFIER);
    // this will populate token and token_secret in consumer
    provider.retrieveAccessToken(verifier);
}

At this point you can call consumet#getToken() and consumer#getTokenSecret() to get and save token/secret for subsequent calls. According to Twitter – access token will not expire unless revoked by user

Posting update

Well, congrats – if you were able to execute all the steps above you now ready to post your first update. Here’s the code that will do it

        // create a request that requires authentication
        HttpPost post = new HttpPost("http://twitter.com/statuses/update.xml");
        final List nvps = new ArrayList();
        // 'status' here is the update value you collect from UI
        nvps.add(new BasicNameValuePair("status", status));
        post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
        // set this to avoid 417 error (Expectation Failed)
        post.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
        // sign the request
        consumer.sign(post);
        // send the request
        final HttpResponse response = client.execute(post);
        // response status should be 200 OK
        int statusCode = response.getStatusLine().getStatusCode();
        final String reason = response.getStatusLine().getReasonPhrase();
        // release connection
        response.getEntity().consumeContent();
        if (statusCode != 200) {
            Log.e("TwitterConnector", reason);
            throw new OAuthNotAuthorizedException();
        }

Now – you can use different update URL to get JSON for example, but generally you can use code above to sign any of your Twitter requests.
Happy Twitting!!

P.S. If you decide to re-post this article please kindly provide link back to the original. And if you have Android phone checkout DroidIn - LinkedIn app.

Posted in Android, Twitter, Web stuff.

Tagged with , , .

This website uses IntenseDebate comments, but they are not currently loaded because either your browser doesn't support JavaScript, or they didn't load fast enough.


53 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Radzell says

    For the posting new things to twitter where is the input. Where would i put the code so i can put the string for app user.

  2. droidin says

    Maybe I don't understand the question. If you are talking about collecting the input that you want to end up on Twitter then you can have a textbox with a button. Get the value from the box, call it "status" and when user clicks the button – execute very last code snippet I put on this page. This particular line adds the value as POST parameter to the request
    nvps.add(new BasicNameValuePair("status", status));

  3. Radzell says

    Does your application run in a Web Browser or a Desktop Client?

    Browser uses a Callback URL to return to your App after successfully authentication.
    Client prompts your user to return to your application after approving access.

    How do i use a callback url if you don't have a url to callback to.

    • droidin says

      My application is running on Android phone. Any android activity can be called with URL by using intent filter, the article gives clear example of that. I would read a good Android book before doing any sort of development – this is pretty complicated framework and you have to learn some basics there

    • droidin says

      My application is running on Android phone. Any android activity can be called with URL by using intent filter, the article gives clear example of that. I would read a good Android book before doing any sort of development – this is pretty complicated framework and you have to learn some basics there

  4. Radzell says

    yeah i trying to read a book and develop at the same time i had no idea it would be this difficult, but thanks for the advice.

    • droidin says

      Don't get easily discouraged. What helped me was to look at "real" opensource Android project such as andtweet (http://is.gd/1Rdq7) It is using older REST API but codewise it's just about perfect, you can learn a lot just by looking. Try to pick the basics – activities, intents, services, etc. and look at their lifecycle through the app, everything will become much clearer

  5. Noah says

    Thanks for the article. I'm following along and when I get to the following line:

    provider.retrieveAccessToken(verifier);

    I receive this exception:

    "oauth.signpost.exception.OAuthExpectationFailedException: Authorized request token or token secret not set. Did you retrieve an authorized request token before?"

    Do you know what I can do to solve this problem? Thank you.

    • droidin says

      Yes Noah. I actually discovered it myself. The problem is – when the browser is open, the activity that holds handle to consumer and provider dies, so when you back to it from callback URL, the activity is anew and so are consumer and provider.
      The way (may not be ideal) that I dealt with it – I had to load initial auth request not into standalone browser but into Activity in the same app. Since I save consumer and producer into static class even if 1st activity is stopped the app thread survived and so do consumer and producer. Then the very same callback calls 1st activity (preferences in my case)

      • Noah says

        I created a browser activity and used that to authenticate with Twitter and send the information back. Seems to be working fine now. Thanks again for the great article and quick response!

      • zlu says

        droidin, thanks for the posting, it's very helpful. i have the same problem and couldn't resolve because i don't understand what you said above about "load initial auth request not into standalone browser but into Activity in the same app" and "save consumer and producer into static class". do you mind elaborate?

        • droidin says

          1. You have a choice to call Twitter authentication page in mobile (standalone) browser or inside your app into separate Activity that contains WebView widget
          2. I'm putting these into the static class since I need to guarantee that when I'm making subsequent calls I'm referring to the same consumer/producer and not to the newly created non-initialized objects.
          Hope this helps

          • @wouter88 says

            I dont use the Twitter Oauth but Tripit Oauth (very similar) and I also have this issues. I open the authentication page in my standalone browser and then make a callback. But this is where it goes wrong. it makes a new consumer/producer object. How can I make a static class of these 2 objects? Can you give me some advice?

      • @wouter88 says

        Hey,

        How can i do this:

        "Since I save consumer and producer into static class even if 1st activity is stopped the app thread survived and so do consumer and producer."

        I am trying to authenticate with tripit (with oauth) and I can get my oauth_token but when after the callback new activity is called and I have an new consumer en provider. How can i do this? Thank you,

        Wouter

      • Nicholas says

        Is there a way to persist the provider/consumer through SharedPreferences or some other means? That way when returning from the callback, you could recreate a valid provider/consumer?

  6. ellie says

    i handled this by setting the activity's launch mode in the android manifest so that there is only ever one instance
    android:launchMode="singleInstance"
    see http://developer.android.com/guide/topics/fundame...

    note: if you do this, then you need to handle the return to your activity in onNewIntent(Intent) rather than onResume() …if my understanding is correct… this.getIntent() gives you the intent that started the activity, not the most recent intent that's calling your activity back to the front. The intent passed to onNewIntent(intent) has the info you need.

    i guess it depends on your situation as to what makes more sense… just thought i'd toss this out there since i was running into the same problem

    thanks so much for this sample using oauth/signpost on android – super useful :)

    • droidin says

      Thanks for the tips Ellie, these are very valid points matter of fact – I'm going to try singleInstance right now!

      • droidin says

        Just to let you people know – setting launchMode to "singleInstance" created some funky behavior and I had to turn it off

  7. Ram says

    Hi Droidin, thanks for the detailed info.

    Can you also please provide a list of HTTP requests for using OAuth with Twitter

    For example the first request may be => HTTP GET request with consumer_key and consumer_secret as query string parameters (or HTTP headers ?). Another HTTP message would be from Twitter with the oauth_token etc.

    Seeing a list of these HTTP requests (in sequence) will be very helpful for people like me who know how to send a request, add intent filter etc. but don't know twitter oauth (and aren't writng android code)

    • droidin says

      Hi Ram,

      Oauth-signpost suppose to abstract that level of details. If you are interested on inner-workings of OAuth (and OAuth on Twitter) there's pretty detailed documentation on OAuth site

    • droidin says

      Hi Ram,

      Oauth-signpost suppose to abstract that level of details. If you are interested in inner-workings of OAuth (and OAuth on Twitter) there's pretty detailed documentation on OAuth site

  8. Ram says

    OK thanks, Droidin.
    I'm not writing Java apps, so I can't use Oauth-signpost.

    I had taken a look at the oAuth site, perhaps, I need to review it more closely. For instance, the site seems to indicate that the service provider will return an oauth_token parameter and an oauth_token_secret parameter. However, after auth, my callback url gets an oauth_token parameter from twitter, but not an oauth_secret parameter. Anyway, I'll experiment a bit more.

    Thanks for the response.

    • Gaston says

      Ram,
      The first call to the request URL sends you only a oauth_token , with that you call the access URL to exchange that request token for an access token (the one used for authentication), only there a secret is returned.

      For the first calls you need to sign the params in the Authentication header with an empty string for Token Secret, don't remember the exact order but its somthing like this : UrlEncode(Consumer_Secret)+'&'+UrlEncode(Token_Secret) , that should give you the key to encode the Signature base string using HMAC_SHA1.

      Hope i was helpfull,
      Gaston.
      PS: Im not a native english speaker, sorry if its not clear enough

  9. nEx.Software says

    I cannot for the life of me get this to work. Every single time I get a "Received Authentication Challenge is null" error. I have no clue what I am doing wrong. Any thoughts?

    • droidin says

      Looks like your are passing null for a token. You should use debugger ans step through it and see what are you passing to the call

  10. max says

    Hi there!

    I'm having some trouble with my code :-(. It seems that provider.retrieveRequestToken(CALLBACK_URL) does not work, as the browser is always lauched with "http://www.google.de". Redirecting to "myapp://twitter" is working fine. I just don't know what's going wrong…

    public class HelloAndroid extends Activity {

    private final String CONSUMER_KEY = "…";
    private final String CONSUMER_SECRET = "…";
    private final String CALLBACK_URL = "myapp://twitter";

    CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET, SignatureMethod.HMAC_SHA1);
    OAuthProvider provider = new DefaultOAuthProvider(consumer, "http://twitter.com/oauth/request_token", "http://twitter.com/oauth/access_token", "http://twitter.com/oauth/authorize");
    HttpClient client = new DefaultHttpClient();

    /** Called when the activity is first created. */
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);

    final Button button = new Button(this);
    button.setText("Twitter!");
    setContentView(button);

    final TextView tv = new TextView(this);

    button.setOnClickListener(new View.OnClickListener()
    {
    public void onClick(View v)
    {
    String authUrl = "http://www.google.de";
    try
    {
    authUrl = provider.retrieveRequestToken(CALLBACK_URL);
    tv.setText(authUrl);
    setContentView(tv);
    }
    catch (Exception e) {}

    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));/**/
    }
    });
    }

    Thanks a lot for your help! :-)

    • droidin says

      I would look at the net output with some type of network sniffer. google.de may have some javascript or redirection that prevents proper processing

  11. Tomas says

    This line:
    String verifier = uri.getQueryParameter(OAUTH_VERIFIER);

    Should actually be this:
    String verifier = uri.getQueryParameter(OAuth.OAUTH_VERIFIER);
    or this:
    String verifier = uri.getQueryParameter("oauth_verifier");

    • droidin says

      Well – in my case it's just a static String that holds value "oauth_verifier"

  12. Shiva says

    Thanks for the detailed info. in my application, when browser re-directs, the callback_URL is always taken as the one specified in my twitter application settings. the callback_URL specified programmatically is not considered at all. any idea why this happens?

  13. Shiva says

    Hi Droidin,
    Thanks for this wonderful tutorial. i have a problem with my App in Android. Redirect is always happening to the URL specified in my application settings in Twitter. the URL provided programatically is never considered. Can u tell me some of the causes for this?

    • droidin says

      You may want to get signpost code and debug through your case. Also look at NET traffic with a sniffer such as Firebug

  14. Marc says

    Great post, thanks for sharing!

    One question: it all works fine for me (did the singleInstance fix to handle the exception mentioned in post from Noah), after a successful twitter login via the browser I get sent back to the app. But, the browser is never closed (the one that says "Redirecting you back to the application"). I see that it's still there when I close my app.
    Is that the expected behaviour, or does that have to do with the singleInstance fix? Or has this to do with the fact that you're redirecting back to an app, not a HTTP URL in the browser?

    Regards,
    Marc

    oauth/authorize

    • Nicholas says

      I think this is normal behavior. It is doing the callback to your app, and the browser is just sitting there waiting to be used or shutdown by the OS to free up resources (ad determined by the OS).

  15. jtip says

    Great tutorial. Very helpful!

    Receiving 401 Unauthorized error following client.execute(post);

    Consumer looks like this (XXXX's appear to be valid, double checked consumer key and secret):

    "consumer"= CommonsHttpOAuthConsumer (id=830055661728)
    consumerKey= "XXXXXXXXXXX" (id=830055471400)
    consumerSecret= "XXXXXXXXXXX" (id=830055471496)
    messageSigner= HmacSha1MessageSigner (id=830055661760)
    base64= Base64 (id=830055661784)
    consumerSecret= "XXXXXXXXXXX" (id=830055471496)
    tokenSecret= "XXXXXXXXXXX" (id=830055700408)
    signatureMethod= SignatureMethod (id=830055477184)
    token= "XXXXXXXXXXX" (id=830055699896)

    What am I doing wrong?

  16. Matthew says

    This is useful code, thanks I will be trying it later.

  17. Andrea says

    Here a working example on how to use SignPost and Twitter4J with OAuth: http://code.google.com/p/agirardello/

  18. Sloth says

    If you are constantly getting errors from provider.retrieveRequestToken, MAKE SURE YOUR CLOCK IS SET RIGHT.

  19. Stacia says

    I am getting an error with :
    provider = new DefaultOAuthProvider(consumer,
    "http://twitter.com/oauth/request_token",
    "http://twitter.com/oauth/access_token",
    "http://twitter.com/oauth/authorize");

    saying that the constructor doesn't take consumer string string string, just string string string. What am I doing wrong?

  20. Stacia says

    Also, I am getting SignatureMethod cannot be resolved. What do I do to make that work?

  21. Tato says

    Thank you !!!!

  22. droidin says

    Well the trick here is to come back to the same consumer/producer. In my app I make a singleton which lives in the main thread so until I stay with my app I can (to the certain degree) assume that m y static singleton will survive. That is one reason why I recommend to open Twitter login page in the WebView embedded into your Activity rather than in standalone browser

  23. mg says

    You can create a new consumer and provider.

    You have to save the token and secret (consumer getter) from the first request only to set the token with secret for the new instance of consumer.

    The token and secret have to be set to get the access token and -secret with the secrets of prior valid tokenrequest.

    Easy, no singleton, no webview … :-)

  24. art says

    mg, do you have any thoughts on where to save it, aside from persistent storage, I would love not to have to move away from singleton and webview approach?

    these are my current steps:

    activity initial creation
    provider creation
    go to auth url
    login w/ twitter
    sent back to app
    oncreate is getting called and recreating my provider
    (this is where the token is loss, so when I call retrieveAccessToken, the above error occurs)

  25. art says

    mg, I tried saving the token and token_secret and then recreating the consumer, but now I get this issue.

    Authorization failed (server replied with a 401). This can happen if the consumer key was not correct or the signatures did not match.

    ( My consumer keys is correct but, the signatures are different though when you recreate the consumer with the secret and token)

    Any thoughts or examples you can provide?

  26. mg says

    I use SharedPreferences to save any token and secret.

    1. Retrieve request token …
    … and save CommonsHttpOAuthConsumer.getToken() and CommonsHttpOAuthConsumer.getTokenSecret()

    2. Retrieve access token …
    … create new CommonsHttpOAuthConsumer and set the token and secret from first request (CommonsHttpOAuthConsumer.setTokenWithSecret(saved_token, saved_token_secret)).

  27. art says

    since I'm replying to myself, this is what I ended up doing ……….

    1) request for auth url and tokens
    2) serialize and persist the provider to a file (dont really like it but it works)
    3) send user to twitter auth page
    4) user redirected back to app
    5) deserialize the provider into current activity
    6) request access tokens from twitter

    Taken from here, http://stackoverflow.com/questions/1965568/oauth-...

  28. Kevin says

    Thank you.
    I use the SharedPreferences to save token and secret.

    Then the problem : "Authorized request token or token secret not set. Did you retrieve an authorized request token before?" is fixed.

    But I get another error -> "oauth.signpost.exception.OAuthNotAuthorizedException: Authorization failed (server replied with a 401). This can happen if the consumer key was not correct or the signatures did not match."

    when I use callback method ,then I get an oauth_verifier=szAlKvSv0MpcqVzbHjYMnLJRPY0c8LsLhJb6LXM
    <- Is it right !?
    If it is right , can I use provider.retrieveAccessToken(oauth_verifier) to get the Access token and Token secret ?

    Because I use this oauth_verifier , then I always get the "Authorization failed (server replied with a 401)".

  29. Kevin says

    Thanks all…
    I use webview to open Twitter authentication page, then those problems was fixed.

    Thanks again … ^^

  30. Ivon says

    Sorry ,Can you put the sample code for how to use thw web view?

Continuing the Discussion

  1. The Open Mob for Android(TM): Tutorials and Sample Code linked to this post on August 15, 2009

    [...] Twitter + OAuth: How to do it on Android (tutorial) [...]



Some HTML is OK

or, reply to this post via trackback.