A Tale of 2 Authentications
For the uninitiated, SugarSync and Dropbox are two competing cloud storage providers. While Dropbox seems to have better name recognition, SugarSync provides a better pricing model, and great support across different Operating Systems & Mobile Platforms. However, I’m not here to talk about the merits of the products, I’m here to talk about the APIs, specifically the Authentication methods they use, and what other API developers can learn from them
Dropbox – The first obstacle with a service like Dropbox is authentication. Dropbox uses oAuth v1. While I usually find oAuth documentation confusing (and Dropbox is no exception), it is pretty easy to master with modern toolkits. Within a few minutes, I was able to get my Dropbox request token (in ruby):
dropboxSession = DropboxSession.new('myKey', 'mySecret')
@dropBoxRequestToken = dropboxSession.get_request_token()
As is typical with oAuth, I can then send this request token to dropbox, they request that the user authenticate it, and I receive my access token.
SugarSync – This one is a little different. SugarSync avoids the oAuth route, and instead provides a simple authentication method. You make a call, providing the user’s credentials, as well as your app key & secret, SugarSync responds with an authorization token. As opposed to oAuth, I just have to make a single POST call to https://api.sugarsync.com/authorization, and I’m done in 1 step. Cool, huh?
What’s wrong with Sugar Sync’s authentication model?
I see this after time.
- Developer creates API
- Developer wants to avoid storing user names and passwords, so developer looks at access-token based authentication.
- Developer finds oAuth to be too cumbersome.
- Developer creates one-off token based authentication.
The error is the idea that non-oAuth, token based authentication is any more secure than simplyusing HTTP Basic Authentication (the simplest of all authentication schemes) over SSL. The argument goes like this:
Token Authentication Defender: If we HTTP Basic Authentication, the API clients will either have to store the user name & password, or ask the user for it each time they access the service. We don’t want the clients to store the password, to avoid potential exposure.
Me: How are you going to stop me from storing the password? If I have to get the credentials from the user once, and send it to an “Authorize” call, what is going to stop me from saving it into my database? Nothing.
Some Simple Guidelines
In this particular situation, I’d suggest that the SugarSync team move to an oAuth service. It really is bad practice for their 3rd party apps to gain access to their users credentials. oAuth, which slightly more complicated, provides the separation of concerns that this kind of API needs. SugarSync should worry about username/password verification, and your app should simply sign the requests appropriately.
As for the APIs that I’ll design in the future, I’ll probably follow these (overly general) guidelines
- Is the API intended for a large number of 3rd party apps to access? Is it essentially useless without the user providing credentials? In these cases, oAuth seems like a winner.
- Is this an API mostly for use between various products within the same company? Do I feel comfortable with the client applications passing through a password? In this case, HTTP Basic Auth is the easy way out, both for the API designer and consumer. Just make sure you use SSL.
- Do I have a really, really, really good reason to build a brand new authentication method? Is my problem really unique compared to what Facebook, Twitter, or Dropbox does? Am I prepared to open source some code and write about my solution to prevent it from becoming a one-off monster that the team will regret? If so, maybe, just maybe, I’ll write a new authentication method…
Update 7-31-2012 Since this was written, SugarSync has changed their API to remove the need to store a users password. Definitely a step in the right direction. You can see the process here.