I'm delighted by the simplicity of OAuth 2.0 (as far as its integration into Flask and express takes takes less than five minutes) and the fact that it makes password management someone else's problem.¹ Really, I'm so delighted that I now use it in every browser-based application I maintain, including this blog.
However—and there should always be a however, otherwise, there would be no blog post—I feel that I reached its limits in terms of how I imagine the authentication workflow. There are, for me, three major limitations:
SSL client certificates
It doesn't make friends with other authentication mechanisms. This is a heavy limitation, since makes it impossible to use in a context of SSL client certificates I'm pushing to use on every REST service I maintain.
It provides a terrible user experience with way too many redirects. With poor latency, such as in a subway or a hotel Wi-Fi, this quickly becomes annoying.
OAuth's flaw, in this way, is to rely on client communication only. This makes the exchange unnecessarily complex. If one could afford communication between the application and the authentication service, things become much, much simpler, and have two major benefits: they tremendously (I hope I have serious proof for such a strong word) reduce the bandwidth usage and the number of redirects.
The purpose of the application is to know whether the user authenticated using a third-party service, and if yes, who is this user. This means that the workflow can be as simple as that:
What happens here is that when the user reaches the home page of the application, he may click on the login button which directly directs the user to the authentication service. As soon as he authenticates, the service gets the user back to the application. At this point, the application doesn't know yet if the user was authenticated or not, and does a server-side request to the authentication service. If the user actually authenticated, the service responds with a JSON containing the information about the user, such as the first and last name or the profile picture. If the user only pretended to authenticate, the app will know that through the same request.
It doesn't have a simple, straightforward way to mix high-security authentication with low-security one. OK, that wasn't particularly clear, so let me explain.
In an application, there could be actions which require to be absolutely sure that the user who performs them is the actual user, and there could be other actions which are so minor, that if a hacker would gain access to them, it wouldn't be a big deal. While the ones which are sensitive may require strong passwords, two-factor authentication, or even something more secure, the other ones may, sometimes, be perfectly fine with a simple four-digits pin code.
By chance, in many cases, the actions one needs to perform on a move (in a subway, or when using someone else's PC) are those non security-critical ones. This means that in those circumstances, one can fallback to a less secure but more convenient way to authenticate. In some cases, it could even increase the security; for instance, I'm not particularly happy entering my Google password on a PC I don't trust, and would prefer entering a one-time key.
Everything is an authentication means
A common mistake is to consider that a password reset procedure has something special, which makes it different from... an ordinary authentication.
From users' perspective, it may make sense only because “it was always done this way,” which is not a valid reason. In reality, it's just a mean to get access to the account—probably a laborious mean, but still, nothing more than that.
From developers' perspective, it doesn't make sense whatsoever, makes the business logic much more difficult, and often reduces security. In general, developers focus on the primary authentication mechanism, trying to make it secure (although many are still at the stage at which hashing the password with MD5 would improve security), but completely lose the security perspective when designing the password reset procedure. This leads to techniques such as: “Call us and tell us your birthday date, and we'll reset your password” or “Hey, we e-mailed you the new password” which inevitably leads to public disaster. You can get whatever security you want, 2-factor authentication included, if you give the access away for any account as soon as a guy calls the support, it takes no effort to have whatever access one wants to an account.
Combined with what I said in the previous section, a different way of imagining the system is to consider that the person has one or several strong authentication means, and one or several... less strong ones. As the ordinary ones are used to gain access to all but the most security-critical features of the application, the strong ones allow to manage the authentication means themselves. In practice, it gives a very intuitive way of handling account security for the user. Imagine a user has three authentication means:
An access with a simple PIN doesn't get much access. An access with a smart card, being much more secure, gives access to the maximum number of features. One of the features is to be able to add other authentication means.
Currently, the problem is that if the user loses his smart card or forgets the PIN code, there is nothing he can do to access the account. This is unfortunate. To be safe, the user can add another level four authentication means:
Here, the user added Facebook OpenID with 2-factor authentication, because it is simple and straightforward, but it doesn't give too much access. To have a recover capability, the user also added a level four procedure which makes it possible to reset the password by security staff after showing an ID.
This leads to a clear, easy to understand system which can integrate without much difficulty more original ways to authenticate, such as SSL client certificates. Moreover, being intuitive, it increases security by assigning security levels to authentication ways and using those levels to allow or deny specific actions within the system, as well as assuming that everything which results into getting an access to the account is authentication.