OAuth: Why it is Still a Good Solution to Secure Your API
The question of whether OAuth is an effective mechanism for securing back-end resources comes up from time to time. Recently, an API developer asked whether OAuth is the right solution to secure an API that he plans to make available for mobile app development - Why bother with OAuth when it's so easy to defeat?
This API developers concern centered around the risk of app developers using the API in nefarious ways - a concern that the app developer has full access to the information typed in by the user on the web form when an embedded web browser is provided in the app, or that the app developer could easily take a user to their own "spoofed up login page" that looks like the API provider's login page when a full web browser app is used.
All great questions to ask as you consider opening up your API. My take is as follows:
If you are working on an API that will be used by third party developers, then there is no magic bullet that will prevent developers from using your API in bad ways. However I think that OAuth 2.0 helps you reduce the risk.
In fact, I would argue that if you have a web page that lets people log in to your service using a username and password, then the risks that you describe - chiefly, the possibility that a nefarious developer will put up a fake "login page" for your service - are present whether you have an API or not and whether you use OAuth or not.
Rather, I think that there are some risks that OAuth helps you minimize.
For instance, if you simply set up your API using HTTP Basic security, or if you use OAuth 2.0 with the username / password grant type - which allows a developer to send a username and password to your API in one call, and get back a token - then the developer, in all cases, has access to the clear text password without any special hacking. Sure, the developer could be evil and do something bad with it, but more likely the developer will make a mistake or not think and write the password in clear text to her own database, or leave it sitting around on the device unencrypted after the app is uninstalled, or print it out in a debug log that gets stored in the cloud and indexed by Google, and on and on.
On the other hand, the authorization code grant type in OAuth 2.0 requires that you open a web browser window that directs the user to a special authentication page, and the password is entered directly on that form. I am not enough of an iOS developer to know how as a client-side developer you can access those cleartext forms rendered by another site from inside an iOS app, but if you can then that's too bad. I still imagine that an attack like that requires more work than accidentally writing the clear-text password to a log, however.
Either way, once the user is authenticated, then on the mobile device you can store the OAuth token locally, and not the password. The OAuth token is random, long, has a limited lifetime, and can be revoked without affecting the underlying user credentials. So, it's safer to store the token, and not the original password, on the device between app launches, which also reduces risk.
Credential negotiation with all apps eventually comes down to trust. The moment an app goes rogue, a provider can invalidate all of the authorizations that had been granted to that app. Regardless of how you do authentication, the importance of assigning each app a unique set of credentials, which is a fundamental part of both OAuth 1.0 and 2.0, is obvious.
For instance, imagine that a developer DOES use your open, public API to forge a login page and harvest user credentials. If you have good logging and analytics on your API, or user feedback, you will find out eventually, in which case you can immediately revoke the app's credentials.
The provider can also force a password reset for all users of a rogue app, because they know which users had previously granted authorization.
Or, if your API is only open to your own developers, then OAuth requires that an app include its own credentials before making any token requests. It's a lot harder for an evil developer to build an app that spoofs your authentication protocol if they can't get credentials to ask for an OAuth token in the first place.
If the native browser flow is triggered, the best-case is that the end user is already logged in to the service so that no password has to be entered. (Embedded browsers usually get in the way here.)
OAuth 2 gives the app the ability to ask only for scopes it needs and to increase them later, if necessary. That way developers can ask for what they need when they need it.
Like everything in security, it's a matter of reducing risk because you can never totally eliminate it, and I think that OAuth 2.0 helps a lot in this area. OAuth can seem cumbersome and complicated for developers too, but with your end-users’ experience and security top-of-mind, I think OAuth is worth the effort.
And what is the alternative? If you use plain HTTP Basic authentication then the app developer still has access to the clear-text password, and unless you combine it with a separate set of application credentials, you can't disable access to a separate app. If you design some other mechanism that:
- Validates app credentials
- Validates username and password
- Returns a "token"
Then you end up with your own version of OAuth.