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?
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.
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?
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.
@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.
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.
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.
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.
Kind of a whiny rant. All because you have to remove your consumer key before distributing source? Mountain <– molehill.
@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.
“…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).
Remember, kids: “If you are not paying for it, you’re not the customer; you’re the product being sold.”
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.
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?
@Alex what alex said. what do you have to lose?
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……
@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.
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.
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.
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
The same thing is on TweetDeck for Android. Plain-text in the .dex file. LOL.
I totally agree with you nelhage.
@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.
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.
[...] OAuth for Open Source clients After reading these two articles about how to compromise Twitter tokens from a client and about how Twitter [...]
Bug is over :(
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?