The new Apple TV opens up a world of possibilities for developers and consumers alike. But, when it comes to text entry, it still leaves much to be desired. So when we set out to design Airbnb for Apple TV, it was clear that requiring a person to enter their email address and password was not the delightful experience we wanted to provide. Moreover, Airbnb allows users to authenticate via third-party services like Facebook and Google. As such, even though entering usernames and passwords is a bit easier with voice entry in tvOS 9.2, such a strategy would only address a subset of our user base.
When someone already has the Airbnb mobile app installed, there are clever ways that we could implement authentication with no typing at all (see Voucher, which facilitates “keyless” authentication in the presence of a sibling iOS application). However, since we can’t depend on all of our Apple TV users having the Airbnb mobile app handy (let alone an up-to-date version) we decided that we first needed to design a general authentication strategy that would work for any Airbnb user. By creating this robust foundation, we would be well-positioned to invest in additional authentication strategies that would provide more seamless experiences for specific subsets of our user base.
When a person wants to log in to the Airbnb Apple TV app, the app provides them with a short code that they enter in their browser at www.airbnb.com/appletv. Once the code has been entered, the Airbnb app is able to retrieve an authentication token from our API which it can use to make subsequent API requests.
This authentication strategy can be broken down into three phases. First, the Apple TV app initializes an authentication request and is given secrets by the server. Next, the person is shown the simple secret and uses it to approve the request by means of an authenticated web session. Finally, the Apple TV app exchanges its secrets for an authorization token usable in future requests. I’ll cover each stage in detail, including code examples for a simple Sinatra-based implementation.
Our first stage is responsible for initializing our authentication attempt. We start from a place of zero trust in the client. The app makes a request to our authentication API requesting new authentication codes. It receives back a freshly generated nonce and short code.
The nonce is the true secret here; it can be thought of as a password. It is critical to use a cryptographically secure pseudo random number generator (CSPRNG) for this purpose. Many common RNGs are susceptible to attack [PDF], and if the RNG is compromised the security of the entire system breaks down. We utilize SecureRandom.uuid from the Ruby standard library for this purpose.
For the short code we prioritize ease of use. Our character set is uppercase alphanumeric with any easily confused symbols removed. This leaves us with a total of twenty six characters. A six character short code then has 26⁶, or 308915776, possible values. Because these codes have a lifespan on the order of seconds to minutes and don’t provide any direct pathway to account takeover even if guessed, this provides sufficient randomness for our purposes. Again, we use SecureRandom as our number generator as a guard against predictable random numbers.
On the server side we use an expiring data store (specifically, Redis) to store data related to the authentication attempt. Our data is keyed by the short code, and the payload includes only a hash of the nonce, generated using bcrypt. It is important to avoid storing plaintext secrets so that if a data store is compromised it doesn’t automatically compromise all accounts.
Our second stage of authentication is responsible for linking the authentication attempt to an active account. The short code generated in stage 1 is displayed to the person and they are prompted to go to an activation URL (www.airbnb.com/appletv) to complete the process.
The web-based activation page requires an authenticated session in order to link a short code to an account. If the person is not logged in they will be pushed to a login or sign up flow. They will be returned to the activation page after they have authenticated. The activation page contains a simple form prompting for the short code. Once it’s submitted a success message is displayed and the user interaction is done.
In this system the short code is the equivalent of a username. On the server we look up the stored short code in Redis and update the payload to include the user’s ID, establishing a link to the account. This endpoint is accessible only to clients who have already established a trusted identity, so we can effectively apply rate limiting to it to prevent abusive attempts to guess short codes.
After the Apple TV app receives the secrets in stage 1 it begins polling the server to see if they have been authorized. Each polling request includes both the short code and the nonce. The polling frequency is provided by the server so that load may be throttled if necessary. Each polling request is used to refresh the lifetime of the generated authentication tokens. Because the server controls both the polling interval and the key expiry, it can ensure that the expiry is sufficiently distant to prevent timeouts while the person is still engaged with the process.
On the server each request leads to a lookup of the short code in Redis. If the hash of the nonce matches the value in the payload then we check for an associated ID.
If there is no ID the expiry is reset and nothing else occurs. If we find an ID then we delete the short code from Redis and generate a session for the associated user. At this point, the person has successfully logged in. The Apple TV may now interact with our API just like any other authenticated client.
At Airbnb we aim to design software that surprises and delights. Building a login flow that doesn’t require entering a password is one of the little ways that we try to get out of the way and let you get on your way. It’s also something we can share with others facing this common challenge. Check out an example implementation of this workflow at https://github.com/airbnb/apple-tv-auth.