Dear Twitter: Stop screwing over your developers.

I really like Twitter. I think it’s a great, fun, service, that helps enable interesting online communities, and is a surprisingly effective way to spread news and information to lots of people online. One of the things that I’ve loved about Twitter is their API, and how open and welcoming they’ve been to developers. I even use Twitter from an IM client that I develop, using protocol support that I wrote myself.

However, as part of the recent transition to OAuth authentication, Twitter has made a number of moves that, in my opinion, show that they just don’t care about the developers that write clients for their service any more. They’re evidently too busy pandering to their large corporate partners and scrambling for sources of income, and they think they’re too cool to have to care about the individual developers who make their service available to such a wide range of users and use styles.

Background: OAuth and consumer secrets

This all started when Twitter transitioned their API’s authorization scheme to OAuth, an open standard for online authentication, that provides a much richer, more powerful, and all-around safer security model than simply handing around passwords in the clear, like Twitter used to require.

As part of the transition, Twitter requires that all applications to obtain a “consumer key” and “consumer secret” with Twitter, which are essentially analogous to a username and password used to identify the application making the API requests.

This is perfectly reasonable for web applications, where the code runs server-side, and so can actually keep and use secrets effectively. However, it’s hopeless on the desktop. We have at this point many years of precedent for the problem of a desktop application having and using a secret key without revealing that secret key to a user willing to dig for it: That’s exactly the problem DRM systems have tried to solve time and time again, and repeatedly failed.

The OAuth specification recognizes this fact, and states,

In many cases, the client application will be under the control of potentially untrusted parties. For example, if the client is a desktop application with freely available source code or an executable binary, an attacker may be able to download a copy for analysis. In such cases, attackers will be able to recover the client credentials.

Accordingly, servers should not use the client credentials alone to verify the identity of the client.

Accordingly, most sane implementations of OAuth, such as Google’s Buzz, don’t require secrets from desktop applications, although they may allow a User-Agent string or similar for apps to voluntarily identify themselves (which may be reflected in UI, for instance).

Twitter, however, blatantly ignores that statement from the OAuth spec, and insists that all applications, even desktop applications, (impossibly) keep their consumer key secret, so that Twitter retains the power to identify which applications are posting what, and the ability to disable applications that are spamming or broken.

When confronted about the impossibility of this requirement, Twitter refused to change their stance, insisting that users instead make a “best effort” attempt to keep their keys secret.

Twitter can (and will) turn off your app

This is, of course, impossible requirement for open-source applications, where the source is to be shared freely. If I want to distribute an open-source application, Twitter requires that I do not distribute a consumer secret, but rather require every user who downloads my source to register their own app (a process that is optimized, in terms of user experience, for developers, and not the average user), and plug it into configuration or into the application. They have held to this position despite the fact that this is an awful user experience for developers or users who want to use an open-source application. I can only conclude that Twitter has decided that small, open-source applications are not worth their worry, and they don’t care about forcing their users to jump through absurd hoops.

Like I said, I develop an open-source Twitter application. I was vaguely aware of Twitter’s policy on consumer secrets, but concluded that their documentation must just be confused, since their requirements seemed utterly unreasonable. Accordingly, when I implemented OAuth support, I just embedded my credentials in my source, to make life easy for all of my users.

Recently, however, after I mentioned Twitter’s broken OAuth policies on Twitter, I received an email from Twitter Support:

It has recently come to our attention that an application registered to you, BarnOwl, has had its Consumer Secret and Key pair posted publicly online

[…]

and as such we’ve reset your API keys and ask that in the future you ensure these are not posted publicly.

And, just like that, my app suddenly appeared broken to every one of my users (they began receiving unhelpful “401 Unauthorized” errors).

Now, in this case, it was my “fault” for posting the key publicly. But suppose I did package my application and made a “best effort” attempt to hide my keys, but some hacker came along, extracted my keys, and posted them online? According to the policy described in that email above, I can only believe that Twitter would also find it necessary to revoke my credentials, again breaking my app for all of my users. As a developer, and as the one who will get blamed if that happens, I’m suddenly a lot less thrilled about writing a Twitter client.

Twitter (and their buddies) are exempt from the rules

Of course, if I’m a big enough player that Twitter cares about my user base, I’m immune. Twitter’s own Android app’s credentials were compromised in a high-profile article on arstechnica, and subsequently tweeted, but I have yet to see Twitter break their own app and lose users because someone else knew how to use strings.

Similarly, gwibber, the microblogging application that ships enabled by default in Ubuntu Lucid, ships its credentials in plain-text in the file /usr/share/gwibber/data/twitter on every recent Ubuntu Lucid machine. But, according to the author of the same Ars article, apparently they’re immune from retribution because Canonical “negotiated a compromise” to allow the app to continue working. Whatever this compromise was, it apparently didn’t involve Canonical making any effort to keep their keys secret.

The message to me here couldn’t be clearer. If you’re a big player, or Twitter itself, your app is immune from takedown by Twitter, because Twitter doesn’t want to offend you or lose your users. But if you’re a little guy, any rogue hacker who knows how to run strings has the ability to cause Twitter to suddenly and mysteriously break your application for everyone who uses it.

Twitter is lying to us about their policies

Twitter has promised that they “don’t discriminate or prioritize anyone on the API, even ourselves”. But, it turns out, Twitter does discriminate. Even as Twitter claims that Basic Auth is deprecated, and “All applications must now use OAuth”, they built a back-door into their API, allowing old versions of their Android client — or anyone pretending to be it — to continue using basic authentication, simply by appending ?source=twitterandroid to their URLs:

$ curl -u nelhage http://api.twitter.com/1/account/rate_limit_status.json
Enter host password for user 'nelhage':
{"remaining_hits":0,
 "hourly_limit":0,
 "reset_time":"Mon Sep 13 00:29:37 +0000 2010",
 "reset_time_in_seconds":1284337777}
$ curl -u nelhage http://api.twitter.com/1/account/rate_limit_status.json?source=twitterandroid
Enter host password for user 'nelhage':
{"remaining_hits":150,
 "reset_time":"Mon Sep 13 00:29:44 +0000 2010",
 "hourly_limit":150,
 "reset_time_in_seconds":1284337784}

When August 31 of this year rolled around, Twitter disabled Basic Authentication for all clients but their own. Even though this flag day was well-publicized to developers, it still caught many developers and users unaware, and users running old versions found their applications suddenly breaking, through no fault of their own – unless they were running Twitter’s own app. Twitter gave itself a free pass to all the pain and frustrated users that everyone else had to cope with.

Aside: What counts as “best-effort”?

I decided to dig into some Twitter applications I or friends use to determine just how well they protect their credentials. How much work do I have to do to be safe from Twitter’s consumer-secret patrol?

The answer, apparently, is “not much”:

Twitter for Android
As mentioned, their keys are in the app’s classes.dex file in plain text. Their keys have been published online, but apparently Twitter doesn’t care.
Seesmic for Android
Same story as Twitter’s app. Plain-text in the .dex, although they haven’t been published online as far as I know.
Gwibber
As mentioned, shipped in plain text with Lucid. Apparently Canonical is a big enough player that they don’t have to follow the rules.
Twirssi

Twirssi embeds Twitter in irssi, a popular IRC client. This is another “small fry”, on a vaguely comparable scale to mine, so I was especially curious what they did. The answer, apparently … is rot13:

 $twit = Net::Twitter->new(
     traits => [ 'API::REST', 'OAuth', 'API::Search' ],
     ( grep tr/a-zA-Z/n-za-mN-ZA-M/, map $_,
       pbafhzre_xrl => 'OMINiOzn4TkqvEjKVioaj',
       pbafhzre_frperg => '0G5xnujYlo34ipvTMftxN9yfwgTPD05ikIR2NCKZ',
     ),
     source => "twirssi",
     ssl    => !Irssi::settings_get_bool("twirssi_avoid_ssl"),
 );
 

Do you feel secure yet?

  1. Sep 13th, 2010 at 09:56 | #1

    Twitter pays lip service to developers and power users because they have been important to growth and adoption. But today what matters to twitter is really big numbers from the unwashed masses, who don’t use free software and in general don’t use third party software.

    Owen Thomas has a good blog post analyzing this at http://venturebeat.com/2010/09/03/twitter-ecosystem-apps/. It comes down to positioning Twitter for acquisition. Investment bankers know how to measure unique users, page views, and the like. They don’t care about the long tail of third party apps.

  2. kodeninja
    Sep 13th, 2010 at 10:56 | #2

    Interesting! So what you’re saying, is that if I just take my Twitter consumer key and secret and, rather than blatantly putting’em in plaintext, do a Caesar cipher on them, my desktop app’s kosher?

  3. Sep 13th, 2010 at 11:05 | #3

    Do they expect Open Source developers to set up a proxy? Perhaps a web app that has both an OAuth consumer and an OAuth provider could make it so it’s not too bad for the users.

  4. Sep 13th, 2010 at 11:05 | #4

    @kodeninja I can’t say that for sure — I’m not Twitter, and they will follow whatever policy they choose. For all I know, they’ll block twirssi now that I’ve made this post (if they do, I apologize to Twirssi’s developers and users for bringing you into this like this, but if they do block you, it was probably going to happen eventually anyways). All I can do is show you what I and others have done, what Twitter has done in response, and speculate on what rules and processes they’re following.

  5. Yoyo Zhou
    Sep 13th, 2010 at 11:42 | #5

    They could have done a fairly trivial search to turn up Barnowl’s key and secret, e.g.

    http://google.com/codesearch?hl=en&start=20&sa=N&q=consumer.%3Fkey\s*%3D+consumer.%3Fsecret\s*%3D+twitter

    Or, one could imagine starting with the consumer key and secret and seeing if they turn up in one’s favorite search engine.

    I would believe the general analysis that Twitter just doesn’t care enough. (Where I come from, we would say “it’s not in their OKRs.”) My speculation is: It’s not important that end users still get fail whales, it’s important that the paying customers (Google, Microsoft, and the other firehose consumers) don’t see an outage. It’s not important that any user or subset of users is able to use Twitter at all, it’s important that the hashtag search shows in a broad sense what people are saying.

  6. Sep 13th, 2010 at 12:01 | #6

    Dear developer, stop developing for a closed platform, and then cry when they don’t meet your expectations of giving a damn about your free work inflating their stock price.

  7. deez
    Sep 13th, 2010 at 13:45 | #7

    Sounds like the solution is to pack one of the blessed key/secret pairs into your app. You could even pack a bunch of them and pick one randomly. Boom, no more registration hassles for you, and no more risk of a bad experience for your users.

  8. Sep 13th, 2010 at 14:08 | #8

    Kind of a whiny rant. All because you have to remove your consumer key before distributing source? Mountain <– molehill.

  9. Sep 13th, 2010 at 14:37 | #9

    @dubious util It’s not just about having to remove the consumer key/secret from my source before distributing it. Obviously, for instance, I distribute open-source software that requires passwords without shipping passwords.

    The problem with that analogy is that the OAuth consumer secret is not intended as a user password — expecting each of my users to register for one, in addition to their account, is a really poor user experience, and one that will drive users away in confusion. And Twitter has to realize that, but doesn’t seem to care.

    The other point here is that Twitter is applying a double standard, and applying different rules to themselves and their partners than they do to everyone else. Obviously it’s their right to apply whatever rules they want to their platform, but I don’t think it’s OK when they claim not to apply such double standards, but then go ahead and do so anyways.

  10. Jim White
    Sep 13th, 2010 at 14:38 | #10

    “…so that Twitter retains the power to identify which applications are posting what, and the ability to disable applications that are spamming or broken.” Twitter has that power over all apps except for evil desktop apps that instruct the user to register his own application and paste the consumer key and secret into the desktop app. Since the app keys and IP address are unique to each user in this case, Twitter is completely powerless to do a global shutdown on the application. The best they can do is shut down an individual user, which they can also do by just suspending his Twitter account(s).

  11. Jonas
    Sep 13th, 2010 at 15:37 | #11

    Remember, kids: “If you are not paying for it, you’re not the customer; you’re the product being sold.”

  12. Sep 13th, 2010 at 16:40 | #12

    Thanks for putting together a good, clear summary of the issues with the OAuth transition for open source developers. Thanks to this my own Twitter client development has been shelved until I can figure out a sane way around it, Twitter changes course, or (most likely) I give up and dive into a new project instead.

  13. Alex
    Sep 13th, 2010 at 17:03 | #13

    I’ll second Deez – sounds like you should just put Twitter’s own key and secret into your app. What are they gonna do, revoke it?

  14. lk
    Sep 13th, 2010 at 19:32 | #14

    @Alex what alex said. what do you have to lose?

  15. Sep 13th, 2010 at 20:19 | #15

    Same stupid thing with Facebook, they need their app ID and secret just as well… Very annoying, as a writer of an open source status reader/updater. Everyone using a desktop app needs to register their own (and no name clashes!) http://developers.facebook.com/docs/authentication/desktop

    facepalm x 1.000.000……

  16. Sep 13th, 2010 at 21:05 | #16

    @Greg If I read Facebook’s documentation correctly, they seem to actually get this more right. The link you said said that desktop apps should use the same flow that javascript apps use. And that link mentions that you need to register for a consumer key and secret, but nowhere does it describe actually using the secret. So while you do still need to register with Facebook, they don’t pretend that your credentials are actually secret.

  17. vavatch
    Sep 14th, 2010 at 04:42 | #17

    Use the android keys and have your app identify as the android app.

    It seems those are the only keys that are immune. It will annoy twitter and demonstrate to them how hopeless their policy is anyway. And you can just update to new android keys as they are released – using strings – until they update their policy.

  18. Tyler Rosolowski
    Sep 14th, 2010 at 05:30 | #18

    The answer is deceptively simple, put the OAuth AppID and secret as a encrypted public download, and automate your client to download it on startup.

    It fixes both your problem of sharing it in the source code, and changing it if the OAuth details get banned by Twitter again.

  19. Sep 14th, 2010 at 09:26 | #19

    If we replace every occurrence of Twitter in this post with Facebook, we would have another blog post in a matter of minutes which would be perfectly valid. Actually my experience as a developer has been by and large good about Twitter. They have been blamed enough for disallowing basic authentication and forcing oAuth at a very short notice. But I found at least there is clarity on different authentication flows. And most importantly they DO understand the need of xAuth unlike Facebook. In fact developers world over believe Facebook is still run by a bunch of college graduates / teenagers and are serious only about advertising and not about developers. This thread should explain the same: http://forum.developers.facebook.net/viewtopic.php?pid=227900#p227900

    As other developers let’s hope better sense prevails.

    Very nice post. #muchNeeded

  20. JJ
    Sep 14th, 2010 at 13:10 | #20

    The same thing is on TweetDeck for Android. Plain-text in the .dex file. LOL.

  21. Westly Ward
    Sep 14th, 2010 at 15:44 | #21

    I totally agree with you nelhage.

  22. jc
    Sep 16th, 2010 at 19:48 | #22

    @Tyler Rosolowski An encrypted public download, eh? And where is the decryption key to be stored, if not in the app? Same problem, just one step removed.

  23. Laurent
    Nov 12th, 2010 at 04:57 | #23

    I and a lot of people use the API with a unique “Consumer” and a unique IP. After more 2000 of high level quality tweets with the same IP its easy to understand the tweets coming from that IP are secure.

    Adding the possibility of defining an IP using the simple security scheme is the simplest and smartest way to resolve a lof of difficulties.

    Years of experience learn us the best security is always something simple with a few lines of code.

    Professional people knows the number of bugs and the number of vulnerabilities is proportional to the number of lines of code.

    So; there is 2 possible scenari is this case; one questioning on professionalism and the other is questioning on bad reasons to force the only use of Oauth.

    One reason can be to stop the flow of the growing number of automated tweets.

    I confirm sometines in the week end the old api is functionning.

  24. Dec 21st, 2010 at 16:23 | #24

    [...] OAuth for Open Source clients After reading these two articles about how to compromise Twitter tokens from a client and about how Twitter [...]

  25. Diego
    Apr 1st, 2011 at 09:16 | #25

    Bug is over :(

  26. Your Mother
    Dec 19th, 2011 at 23:27 | #26

    TweetDeck no longer has Linux support, and Twitter took over that project. Why kill a working branch? Why would they only provide Mac support that is essentially a Linux version with special stupid Apple code?

Leave a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>