Last week my company launched one of our side projects, Qup, to the app store. During the submission process, we ran into a rejection issue that surprised me. Our app uses the Spotify SDK to play songs for small gatherings of people, and the SDK uses a typical OAuth flow for authentication. The rejection from Apple cited rule 10.6:

10.6: Apple and our customers place a high value on simple, refined, creative, well thought through interfaces. They take more work but are worth it. Apple sets a high bar. If your user interface is complex or less than very good, it may be rejected Specifically, your app exits to Safari to log in to/sign up for Spotify. It would be appropriate to revise your app to display the Spotify login/registration page in a native webview, rather than exiting the app completely to Safari, and then returning the user to the app.

I’ve since heard of numerous other app rejections for this same reason.

The rejection seems innocuous enough; Apple is objecting to the user experience of bouncing around from app to app, and wants to eliminate that from the login flow. Spotify did actually release a new version of their SDK that supports an in-app login flow using an embedded web browser, so it was easy enough to fix and (eventually) get approved. However, I couldn’t shake the feeling that there were some very serious security implications that were being glossed over in the pursuit of “better user experience.”

In order for the Spotify SDK to play music inside my app, it has to make sure that the person using the app is actually a Spotify user, so it needs to authenticate. I could just ask the user for their username/password, tell that to the Spotify SDK, and be done with it. There’s a big problem there though — now my app knows your password. If my app were malicious, I could steal your Spotify account, or worse, another account where you’ve used the same password. Even if you trusted my app, there’s always the risk that my app could be hacked.

OAuth can remedy these problems by leveraging a chain of trust. When my app bounces the user out to Safari, the user is placed in a familiar app that they trust, and my app cannot listen in or obtain any information that is exchanged in that session. Safari in turn makes assurances to the user that Spotify.com is actually the real Spotify and not an imposter (by means of a root certificate authority); it’s a chain of trust from the user, to Safari, to Spotify. The user can be confident that only Safari and Spotify can see their password when it’s typed in to the browser.

After Spotify authenticates the user, it passes back a token to Safari, which passes the token to my app. This token can be used to play music with the Spotify SDK, but a malicious entity can’t do much with the token. It expires, and it can’t be used to steal an account (Spotify or otherwise).

When Apple asks for the authentication to happen inside my app with an embedded web browser, the chain of trust is broken. The user should not type their Spotify password into an area where my app could read it. By forcing apps to implement OAuth this way, Apple has negated one of the protocol’s largest advantages. It also promotes bad security habits for users, and reinforces the dangerous assumption that if something “looks like” Spotify it must actually be Spotify and therefore I can type my password.

As one of my colleagues pointed out, perhaps OAuth isn’t the best solution here for mobile. He suggested two-factor authentication as an alternative, however the user experience still involves a third-party app (messages, email, or other way to deliver an authentication code). At the very least, I think Apple should let developers make the choice about the security vs. user experience tradeoff.