Anyone who’s interested in security on the web has probably already heard of OAuth. I’ll skip the details of how OAuth works, since that information is available elsewhere, but here’s the short version (OAuth veterans may choose to skip the next three paragraphs):

Before we get started, let me define a bit of terminology from the OAuth Spec:

  • Service Provider: A web application that allows access via OAuth.
  • User: An individual who has an account with the Service Provider.
  • Consumer: A website or application that uses OAuth to access the Service Provider on behalf of the User.
  • Protected Resource(s): Data controlled by the Service Provider, which the Consumer can access through authentication.

API authentication is tricky. The naive approach is to have third party (Consumer) applications ask the User for their credentials, and pass them along to the Service Provider for authentication. This is bad. Even if the User trusts the Consumer, you’re telling people that it’s Ok to give out their secret credentials. Think how much more successful phishing would be if users were legitimately asked on a regular basis to provide account information via email. There are more subtle problems, too: it’s impossible to give Consumers different access levels, impossible to revoke access for a particular Consumer, and there’s no central place that tells a User which Consumers have access to their account.

OAuth solves all these problems by having the Consumer authenticate with the Service Provider, and allowing the User to grant Consumers access to their Protected Resources. Consumers never touch User credentials. In fact, they don’t even need to know who the user is. The level of access the Consumer has is entirely up to the Service Provider and the User. Access control can be managed at the Service Provider, where a central list of linked Consumers can be displayed. Since each Consumer is given a unique access token, different permissions can be granted to each.

OAuth on the iPhone

For the past couple months, I’ve been working on and off building a native iPhone application for Pownce. The Pownce API uses OAuth for authentication, which I wanted to use on the iPhone. But for the OAuth flow to work, the User must be directed to an authorization page on the Service Provider’s web site. This poses a problem for native iPhone applications — the iPhone can only run one application at a time, so opening the authorization URL in Safari terminates the Consumer application.

But there’s a solution. The iPhone allows native applications to register with the OS to handle certain URL schemes. By registering pownce:// and instructing the Service Provider to redirect the User to pownce://access_token after authorization, the native Pownce application is automatically relaunched. The flow looks something like this:

Pownce - Pre-AuthorizationPownce - Mobile Auth ScreenPownce - Post-Authorization

A couple of days before the app store opened, I demoed the soon-to-be-released Pownce iPhone app to a group of folks at the OAuth Summit. Following the summit, Chris Messina, Simon Willison, and others pointed to Pownce as an example of “the right way” to use OAuth on the iPhone. Everything seemed great… until the app store launched.

The Problem…

Turns out Chris Messina and Simon Willison aren’t your average User. They understood why Safari was being launched. The average User didn’t. We started getting reviews in the app store complaining about the auth flow, and early statistics show that nearly 40% of users who downloaded the Pownce application never linked it with a Pownce account (there are other reasons a user might never link their account, but I’m sure the auth flow contributed — if anyone has stats for another app as a point of comparison, I’d love to see them). Needless to say, this situation is not good.

The Solution?

The naive solution is simple. The iPhone SDK provides a UIWebView control that lets applications integrate a web page with their UI. Instead of launching Safari, a Consumer could use a UIWebView to integrate the authorization page with the rest of their application. But this solution is not ideal because the User has no way of knowing whether they’re actually looking at the Service Provider’s site, or a fake. (In reality, as Eston Bond pointed out to me, the entire OAuth flow from the Pownce app to Safari and back could be faked fairly easily too, but I’ll conveniently ignore that for now).

The solution here, I think, is to have some mechanism (other than the URL and browser chrome) that gives the User a clear indication as to whether or not they’re on the Service Provider’s site. Something like Bank of America’s SiteKey would work perfectly. The Service Provider could split the authorization process into two steps. The first step would simply ask for a username and display a CAPTCHA. The second step would display an image that the User has previously selected, and prompt for a password. If the User doesn’t recognize the image in the second step, they should be suspicious.

The obvious downside is that the Service Provider needs to ask every User to choose a security image prior to the authorization process. SiteKey is also susceptible to man-in-the-middle attacks, but that might be solvable using a CAPTCHA in the first step of the authorization process (I haven’t thought too hard about it). In any case, I’d love to hear what the community has to say on this particular topic. There’s an obvious balancing act going on here between usability and security. What’s the optimal mix?