Implementation Details: Distributed Identity
The very first message sent over the precursor to the Internet was a log in attempt. Unfortunately, the system crashed part though, so the very first try was just “LO”. Since then, the explosion of networked systems has lead to an explosion systems to log in to.
The core problem of a log in system is authentication: knowing I am me, and other people aren’t. Traditionally we would solve this problems by claiming to be someone — giving a username — and then proving we are them using something that has previously been recorded by the system, and has a reliable security property.
We could use something someone knows (like a password), which is not know to other people. We could use something we have (like a keycard), that other people do not have. Finally we could use something we are (like a fingerprint), choosing some feature that other people wont be able to fake.
Each one of these is known as a factor, and in the recent years two-factor logins have become more popular, such as using a bank card (something we have) to generate an login code when we sign in with our regular password (something we know) to our bank website, thus increasing the challenge to a person attempting to pretend to be us, and lessening the chance of someone doing so accidentally.
In this world, encompassing much of the 80s and 90s, we were done — sufficiently complicated passwords and second factors from the likes of RSA kept the bad guys out of our accounts. The growth of the web opened up a whole new set of problems though. Whereas before we had generally needed to log in to few system regularly, we now had to consider many different websites, many of which we used infrequently.
This lead to a problematic expansion of the number of logins and passwords people needed to remember, and that lead to short cuts. Reusing the same password in multiple places lets hackers who can break in to the weakest one log in to any of them, and writing passwords down can result in an equally juicy target. Companies like LastPass and OnePass started to provide password managers, and browser and OS vendors built credential stores into their systems, but for the majority of users the problems remained.
Distribution, Federation or Delegation
Luckily, we had an extremely potent arrow in the quiver — distributed identity, or delegated authentication. Giving every system a login and password encouraged users to treat them all as equal: your internet service provider is not that different from your crochet forum. But even from the system’s point of view, that wasn’t true — your ISP needs to bill you, and offer an interface for support. They need to know your phone number, and home address. The crochet forum, probably, doesn’t care. The amount of effort towards security these different systems provided was significant, and the prevalent re-use of password put a strong onus on developers of smaller systems to care more about security, an need many didn’t satisfy.
Developers began to realise that they didn’t really care who the user was — they just cared they were who they said they were. Email was the first great universal identifier — email@example.com is a unique reference to that email account, and it is something I can easily prove access too: you just need to send me some verification message via email which I can repeat back to you. In this way an email address becomes the username, and the verification code becomes the password. The big difference is that the ‘password’ is not something that you need to remember or write down — the security comes from the process, not the specific value.
A very large percentage of the web’s authentication systems work this way, except they generally refer to it as a “forgot password” function rather than the primary authentication method — which was, and is, still commonly a username and password. There were some valuable lessons in the email address approach though. It was delegating the verification of an identifier to another system, the email provider, and that worked really well. It was also making use of a reliable, global namespace, which allows for a decent level of security. Both of these ideas would be played out several more times, most notably with a project called OpenID.
OpenID initially started as YADIS, Yet Another Distributed Identity System, one of the many ideas that sprung from the mind of Brad Fitzpatrick during his time at LiveJournal. He realised that domain names had the similar properties to email addresses — they could be globally resolved to a certain place, and you could prove access to them. Email address though was a key piece of information — in fact, it was something that many users would prefer not to give out, if they could avoid that. He designed a system where users could give a domain name instead, and have their identity without that domain be verified by software running on the domain itself.
This was another type of delegation of authentication — handing it off to some other services, but with a rather more formal method of asserting an identifier. A forgot password generally did this by the site generating a hard to guess code, emailing it to the user, and the user clicking a link which returns them to the site with the code in toe. Presenting the correct token confirms you have access to the email account, and hence are the user identified by that email address.
In OpenID, the same kind of process was followed: the user signed in to a site by giving the domain where their identity was hosted, and the site redirected the user over to it with a unique reference. The site that consumed the identity, or allowed sign in with OpenID, was referred to as the Relying Party (RP), and the one that provided the identifier was the Identity Provider (IDP). When the user was send to it, the IDP did whatever it needed to to trust the user, and redirected them back to the RP with an assertion of an identity. This let the RP confidently associate an identity from the IDP with the user that was accessing at the time.
Importantly, this didn’t give the RP any particular access to the IDP — if I signed in to a forum using Google as an OpenID provider, the forum got no access to my Google account.
While laudable, it turned out that no access wasn’t quite what people needed. OpenID exposed a method for sharing extra sets of data with RPs, but it was cumbersome — so around 2007 engineers at a number of social websites came up with a process for performing authorization over the web using the familiar OpenID redirect model. OAuth, the system they created, was later improved on with OAuth 2.0, which primarily replaced a fairly complicated signing and security mechanism with an explicit dependency on the security of TLS (or SSL), as used in https:// communication across the web.
OAuth involved a RP and an IDP, but rather than the IDP returning an identity assertion, it would return a special kind of cookie, an access token. This token didn’t authenticate the user (say who they were) — it authorized the Relying Party to access certain facilities on behalf of the IDP user. The token behaved as a valet key — it let other people take some actions on your behalf, without giving them full control.
For example, an OAuth token may be granted the ability to post to your stream on a social network, but not to access your friends on that network. The Relying Party would be able to take one action, but be blocked from taking the other.
The authorization/authentication distinction was quickly blurred, as one of the primary services many IDPs offered was an identity services: call this service with the right access token and we’ll give you information about the user that it was granted on behalf of. This led in later years to the development of a unifying approach known as OpenID Connect. This provides the RP with both the access token of OAuth and an identity assertion (referred to as an ID Token) that allows lightweight verification of who the user is, for use in a delegated sign in situation.
The ID token is a simple JSON object which includes an identifier for the user, the party who created the assertion, and some ancillary details, all of which are cryptographically signed. This signature can be verified by anyone with access to the IDPs public certificates, which means consumers can trust that the token was generated by the IDP on behalf of the user indicated.
Part of why the OpenID/OAuth log in experience was a good one (and usually much faster than email based systems) was that the web came with a mechanism of ambient authentication, in the form of cookies. Cookies sit in a browser, and most of the time stick around from user session to session. OpenID, or something like it, could function quite well with the user having to log in to the IDP each time they wanted to sign in to a Relying Party, but cookies meant that most of the time the IDP already knew who they were, and could redirect them swiftly.
This was one of the challenges with native mobile applications, particularly in the wake of the iPhone in 2007 and Android in 2008. There was no cookie jar to manage ambient auth, and no reliable redirection mechanism in place to provide a clear replica of the web model. Both Android and iOS eventually settled on two techniques to re-establish ambient credentials: out-of-process web views, and system authentication providers.
The more obvious approach was system authentication providers. On Android, any app can register an Account with the system AccountManager which can be used store store credential information, initially a username and password but more commonly a cookie or session identifier. This could then be used to bootstrap authentication into other services — Google, Facebook and LinkedIn (among others) all offering third-party sign in backed by this account manager approach. On iOS, system level authentication came a little later, and with a predefined list of partners. Twitter lead the pack, but system was soon expanded to include system level authentication for Facebook, Weibo and others. This was primarily intended to support the rise of OAuth based access to services, such as being able to post a Tweet, but worked just as well for providing delegated sign in.
The second approach was to re-use the cookie jar that had worked so well on the web. Many apps had implemented auth delegation using a webview — a web rendering library that ran as part of the containing app. This worked, but had a couple of problems. The first was that webviews can be snooped on by unscrupulous host apps, meaning a rogue application could potentially grab the credentials to your IDP account as you typed them in, or send you to a fake version of the IDP to capture your details. The second problem is that the webviews are transient, and app specific — you have to log in to the IDP itself each time you want to log in to a RP application.
The alternative was to switch out from the app to the system browser. This couldn’t be snooped on, and would have cookies, so if you had previously logged in to your IDP it was probably still authorized. The problem here was that the user switched entirely over to a web browser, and so if there was a issue could easily be left outside the app, which wasn’t something most developers wanted.
The solution implemented by Chrome Custom Tabs on Android and SFSafariViewController on iOS was to make a special kind of webview available that was in effect a limited access view of the system browser. The developer could trigger display of the view from within their app, but the resulting browser would be running outside of their process, with access to the cookie jars of the main browser. This allowed much safer sign in for users, without the risk for developers of dumping their users in the browser without a route back.
Having reliable access to ambient credentials offers some interesting new options to developers — features like Google Sign In’s cross-device seamless sign on work because the system can determine who the user is, who the app is, and whether they have granted access to the app on a different platform: if they have, it can sign them in to the app without requiring any user interaction. However, in parallel to this extension of the traditional delegated authentication options, many developers started building for mobile devices first, and taking advantage of an alternative.
Instead of relying on the web-centric world of email addresses, passwords, and delegated auth, apps like WhatsApp took their cue from the fact that phones were phones, and had phone numbers. A phone number was reliable, cheap to verify (much like email, send a hard to guess code over SMS, and check whether the phone receives it) and came with a built-in friend list. Access to phone numbers and the address book was easy to get on iOS (where for a while it required no permission) and Android, and allowed an app to get up and running quickly. It also appealed to a new generation of users that were getting online for the first time with a mobile device, and didn’t have a history of web services or email accounts to use for sign in.
The primacy of email as the notification channel was challenged with SMS and APNS/GCM push notifications. Each app would store session cookies indicating the authentication state, which allowed for phone numbers to be changed without the user’s identity being replaced, and the explosive growth of these apps indicated the value of the contact list as a network.
What Have We Learned
For all of the technical change, we haven’t change the fundamentals of authentication all that much. The password was enhanced with 2-factor authentication, and avoided with delegation or verification of stable and reliable identifiers — your email, social network, or phone number.
The tools we have for managing user identity have also remain remarkably unchanged — hard to guess session identifiers in long lived client-side stores, with limited access credentials as a subset of them for delegated access, and assertions of identity with cryptographic assurances of their validity.
Of more note are the range of practices developed to provide a smooth user experience through use of ambient authentication, to engender user trust through clear authorization techniques, and to improve security through a whole host of heuristics and indicators of normal usage.
The challenge all major authentication providers now face is how to extend their models to emerging markets, where many of our given assumptions (single user devices, access to email, or reliable data connections for example) no longer hold, and to extend the authorization model to encompass the mix of sharing and privacy that lets users collaborate and compartmentalise their use of apps and services.