OpenYOLO: In-Context Credential Management

draft-openyolo-web-00
I. McGinniss
Google, Inc.
Published
May 2, 2017
Expires
November 3, 2017

Abstract

OpenYOLO for Web is a protocol for retrieving, updating and assisting in the creation of authentication credentials. This document describes the core concepts of OpenYOLO, and platform-specific details for implementing the OpenYOLO protocol for Progressive Web Applications (PWAs).

What's in a name?

YOLO stands for "You Only Login Once", which is the internal code-name for Google's Smart Lock for Passwords API on Android. OpenYOLO is the open standards successor to YOLO, and came to be as a result of an initial collaboration between Google and Dashlane. OpenYOLO leverages the lessons learned from YOLO, and also ensures that implementations of OpenYOLO can compete on a level playing field.

OpenYOLO would not have been likely to succeed without AgileBits, Keeper Security and LastPass, to whom we are grateful for their continued support and engagement.


Copyright notice

Copyright (c) 2017 The OpenID Foundation.

The OpenID Foundation (OIDF) grants to any Contributor, developer, implementer, or other interested party a non-exclusive, royalty free, worldwide copyright license to reproduce, prepare derivative works from, distribute, perform and display, this Implementers Draft or Final Specification solely for the purposes of (i) developing specifications, and (ii) implementing Implementers Drafts and Final Specifications based on such documents, provided that attribution be made to the OIDF as the source of the material, but that such attribution does not indicate an endorsement by the OIDF.

The technology described in this specification was made available from contributions from various sources, including members of the OpenID Foundation and others. Although the OpenID Foundation has taken steps to help ensure that the technology is available for distribution, it takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this specification or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any independent effort to identify any such rights. The OpenID Foundation and the contributors to this specification make no (and hereby expressly disclaim any) warranties (express, implied, or otherwise), including implied warranties of merchantability, non-infringement, fitness for a particular purpose, or title, related to this specification, and the entire risk as to implementing this specification is assumed by the implementer. The OpenID Intellectual Property Rights policy requires contributors to offer a patent promise not to assert certain patent claims against other contributors and against implementers. The OpenID Foundation invites any interested party to bring to its attention any copyrights, patents, patent applications, or other proprietary rights that may cover technology that may be required to practice this specification.

Requirements Notation and Conventions

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.


1. Introduction

Manually authenticating in an app or site is mentally exhausting. Users are typically presented with a screen like the following when interacting with an application or website:

+------------------------------------------+
|                                          |
|       To continue, please sign in:       |
|                                          |
|    Email                                 |
|   ------------------------------------   |
|                                          |
|    Password                              |
|   ------------------------------------   |
|                                          |
|   Forgotten your password? [Click here]  |
|                                          |
|   =============== Or: ================   |
|                                          |
|   +-------------+     +--------------+   |
|   |   Google    |     |   Facebook   |   |
|   +-------------+     +--------------+   |
|                                          |
|       If you don't have an account,      |
|                [click here]              |
|                                          |
+------------------------------------------+

The user typically has to mentally process three questions in response to such a page:

  1. Do I already have an account for this service?
  2. If so, did I use an email address and password, or one of the identity provider options?
  3. If I used an email address and password, what was the password?

For all but most frequently used apps and websites (henceforth referred to as services), this is a tedious and error-prone process. As of 2016, users typically interact with around 100 services. Many of those services are used less than once a month, for example to buy flowers or arrange air travel. Switching to a new device is a particularly painful experience due to the need to re-authenticate with all used services.

Remembering unique account details for 100+ services is infeasible; the natural human consequence of this situation is widespread credential reuse across services. This is a disaster for the user's security - an alternative approach is needed.

1.1. Password authentication

Password based authentication, despite many attempts to displace it, remains the most common form of authentication in use today. Password authentication suffers from three key issues:

  • User selected passwords are often weak. Most users do not know how to produce high entropy passwords. The basic strategies employed involve using combinations of common dictionary words, years and names, all of which easily succumb to social engineering and dictionary attacks.

  • Password credentials are often transferable. The limits of humans to memorize long strings of random information is well studied; the typical user cannot be expected to memorize more than 5 passwords for unrelated services. The natural consequence is that users frequently reuse their passwords, which when combined with email addresses as identifiers, makes the credentials transferable across unrelated services. If a password is uncovered for a user on one service, an attacker can simply try this credential on other services with a high success rate.

  • Password credentials are often long lived. There is no intrinsic expiration time on a password credential, and password rotation is not uniformly enforced across all password using services. If a password is uncovered by an attacker, it can be used for a significant period of time, perhaps indefinitely.

    Even where a service does enforce password rotation, such as once a year, "digit rotation" is commonly employed by users to circumvent this: they simply increment a counter at some position in the password, typically at the end. This makes guessing future passwords from current passwords particularly easy for an attacker.

The problems that passwords cause only get worse as users interact with more and more services. Yet, password authentication persists:

  • Password authentication is familiar to users, and is therefore is often their default choice.

  • It is considered to be easy to implement, despite the numerous account system breaches that demonstrate the opposite.

  • It has no dependencies on external entities, like identity providers. The stability of the system is entirely under the control of the implementer, for better or worse.

It is unlikely that password based authentication can be completely displaced; as such, any solution in this problem space will have to accommodate password based authentication.

1.2. Federated authentication

Federated authentication, in the form of OAuth2 and OpenID Connect, solves the problem of account overload by centralizing authentication for the user with a small number of trusted identity providers. Furthermore, by providing proof of authentication to a service (referred to as a relying party in this context) in the form of cryptographically signed ID tokens, overall security is significantly improved when compared to password based authentication.

However, the success of federated authentication is still limited - OAuth2 and OpenID Connect are regarded as difficult to implement, and federated authentication was unnecessarily tainted by "social login" in the early 2010s. Federated authentication became associated with unnecessary and invasive sharing of personal information. This association has largely been undone, but the perception of privacy invasion lingers.

Furthermore, it is easy for users to forget which identity provider they use, when multiple options are presented. Services also rarely implement account linking correctly, where multiple authentication methods are attached to the same core account. Because of this, making the wrong choice often leads to a totally different account: for example, choosing Google Sign-in when the user's account was actually created using Facebook. The inconsistency and frustration caused by this is often enough to drive users to the authentication method they know best - email and password authentication, with a reused password across every service.

1.3. Account recovery based authentication

An equally common method of authentication employed by users is to simply trigger the account recovery flow every time they need to use the service. Accounts are typically created with a recovery email address or phone number, and users exploit this fact to regain access to the account when necessary. They expect the following flow:

  1. An email or SMS message will be sent containing a link to reset the password.

  2. The user clicks the link to change their password, likely to either their current reused password, or something else that they immediately forget.

  3. The user is now authenticated. When the session expires or the user changes device the process is often repeated.

We shall refer to this method of authentication as "proof of access" - by demonstrating that a secret can be communicated via some trusted side-channel, the user can gain access to the account. Some services use this method explicitly, as the main form of authentication - Slack refers to this as "magic link" authentication.

Sending an authentication secret (a code or a link) to an email address or phone number is essentially a form of federated authentication. In comparison to OpenID Connect, this is a rather absurd and inconvenient, as it requires the user to manually drive the authentication flow. It is, however, a model of authentication that users find easy to understand, despite its shortcomings.

If it were possible to provide proof of access to an email address or phone number directly to a service from an authoritative source, then the manual verification of access to that email or phone number would be unnecessary. The most common email providers are also OAuth2 or OpenID Connect identity providers: Google, Microsoft and Yahoo account for over 90% of the US market, according to a data analysis conducted by MailChimp in 2015. These providers already have the ability to assert proof of access in the form of ID tokens. Providing an easier mechanism to acquire such ID tokens would simplify authentication for many services.

1.4. Credential managers

A credential manager is a piece of software that remembers credentials on behalf of a user. Most credential managers focus on password based authentication, and offer to generate strong, unique password for each new service a user interacts with.

The most common credential manager that users encounter is their web browser, which presents itself via form-fill on authentication pages. Technically knowledgeable users often also have a standalone credential manager.

Credential managers suffer from the following usability issues, which limit their appeal:

  • When a credential manager is a standalone application, the user must manually switch context to find the relevant credential, and copy-paste it to the service they are signing in to. Browser extensions can make this easier, but are not supported on all platforms, in particular on mobile devices.

    Manually copying a password also represents a security risk in itself; on some platforms it is possible for other applications installed on the device to monitor the clipboard and steal passwords that are copied out of the credential manager.

  • Where a credential manager is able to integrate with the browser or OS in some way, heuristics are often necessary to detect and fill in login forms. Such heuristics are fragile to changes in the service, such as when they are redesigned or change path within the domain. Heuristics are employed because there is rarely any viable alternative: services do not provide sufficient information for a credential manager to do a better job.

    This problem is particularly acute when the login system employs an identifier first pattern, where collection of the identifier and a password are split across separate screens. In such situations, heuristics typically fail to detect the relationship between the fields across these separate screens.

  • Credential managers are often blind to relationships between apps and sites that share the same authentication system - saving a credential for one site does not automatically make this credential available on other, related sites.

  • Credential managers do not assist federated authentication: they cannot help the user remember if they signed in to the service using Google or Facebook, only whether they filled in an identifier and password.

  • Credential managers are unaware of password restrictions in use on the site: how long they must be, whether they must include a number or symbol, etc. As such, password generation is also heuristic and based on a least common denominator schema that is acceptable to the majority of services.

1.5. Solution: Direct communication with a credential manager

If services could directly communicate with the user's preferred credential manager, manual authentication and its associated problems can completely disappear. If such a communication channel existed, then the following operations would be possible:

  • Account creation facilitated by the credential manager. The service could describe to the credential manager what authentication methods it supports, and what password restrictions it has. In response, a credential provider could (with or without user assistance) select an email address and generate a strong, unique password that is guaranteed to work.

  • Automatic retrieval of existing credentials. At the appropriate moment, a service could request a credential, and have this automatically returned, or returned after some in-context user consent is solicited. This would be a marked improvement over the user manually finding and copying the credential, and minimizes the opportunity for the credential to be stolen in doing so.

  • Maintenance of the credential manager store. When the service modifies an account, it can notify the credential manager of account changes. This information can be used to keep the credential store fresh.

  • "Proof of access" to email addresses and phone numbers (as described in the Section 1.3 section above) could be directly solicited. While the credential manager might not have the authority to generate an ID token for a given email address, it could facilitate this process.

OpenYOLO defines a protocol for direct communication between services and credential managers, in order to enable these operations.


2. OpenYOLO concepts and definitions

Before providing a high level overview of the OpenYOLO operations, some terms that will be used throughout the specification must be defined. Where data structures are described, this document uses protocol buffer v3 messages as the definition language. Where specific instances of these messages are presented, the Protocol Buffer v3 JSON encoding is used.

2.1. Credentials

A credential is a set of properties that are used to help authenticate a user. Credentials can be partial, where they do not provide all necessary information for authentication.

Credentials in OpenYOLO are composed of the following properties:

  • An authentication domain, where the credential was saved. All credentials MUST have an associated authentication domain. A credential MAY be usable on other authentication domains. Authentication domains are described in more detail in Section 2.4.

  • An authentication method, which describes the system used to verify the credential. All credentials MUST have an associated authentication method. Authentication methods are described in more detail in Section 2.5.

  • An identifier, which designates an account in the context of both the authentication domain and method. All credentials MUST have an identifier. Typically, identifiers are email addresses, phone numbers, or some printable unicode string. Identifiers are typically human readable and distinguishable, but this is not a requirement.

  • An optional display name, that assists the user in identifying and distinguishing credentials. Typically, the display name for a credential is the user's real name, or a chosen alias.

  • An optional display picture, that fulfills a similar role to display name. Typically, the display picture is either a picture of the user, an avatar that they have chosen, or one they been assigned.

  • An optional password, which is a human-readable secret used to authenticate with the service. Specifically, this field MUST NOT be used to store secrets that a user would not use directly, such as bearer tokens.

  • An optional ID token, which provides "proof of access" to the identifier of the credential such as an email address or phone number.

  • An optional set of non-standard properties. This provides the ability for credential providers to innovate within the constraints of the specification, with a view to later standardizing useful properties. Services SHOULD NOT rely upon additional properties, as their meaning is unlikely to be consistent across credential providers.

A credential is represented by the following protocol buffer message:

message Credential {
  // required
  string id = 1;

  // required
  AuthenticationDomain auth_domain = 2;

  // required
  AuthenticationMethod auth_method = 3;

  string display_name = 4;
  string display_picture_uri = 5;
  string password = 6;
  string id_token = 7;
  map<string, bytes> additional_props = 8;
}

For example, an email and password credential could look like:

{
  "id": "[email protected]",
  "auth_domain": {
    "uri": "https://www.example.com"
  },
  "auth_method": {
    "uri": "openyolo://email"
  },
  "display_name": "Jane Doe",
  "display_picture_uri": "https://www.robohash.org/jdoe",
  "password": "RiverClyde7"
}

2.1.1. Hints

Hints are a variant of credentials that are tailored to account discovery and new account creation. They are represented by a separate protocol buffer message from credentials, in order to allow for future extension that might diverge from the definition of credentials. Hints are represented by the following protocol buffer message:

message Hint {
  // required
  string id = 1;

  // required
  AuthenticationMethod auth_method = 3;

  string display_name = 4;
  string display_picture_uri = 5;
  string generated_password = 6;
  string id_token = 7;
  map<string, bytes> additional_props = 8;
}

The two main differences from credentials are that noo authentication domain is declared, and that the password field is renamed to generated_password, to express its intent more clearly.

2.2. Credential providers

A credential provider is a credential manager which implements the OpenYOLO protocol. Credential providers are typically one of the following:

  • A dedicated service whose sole purpose is to store and recall credentials for the user.

  • A web browser or custom input method, which provides credential management, but not as its primary focus.

  • An operating system service, such as Smart Lock for Passwords on Android or Keychain on iOS.

2.2.1. Known, unknown and preferred providers

Given the sensitive nature of the data being exchanged by the OpenYOLO protocol, it will become a target for attackers. A likely attack is for a suspicious service to implement the OpenYOLO protocol and attempt to register themselves as the user's credential provider. Distinguishing legitimate credential providers from malicious providers is therefore an important aspect of building trust in the protocol, for both service maintainers and users.

In order to achieve this, a known provider list will be maintained by the OpenID Foundation. A static snapshot of this list is included in the OpenYOLO API on each platform, and will be automatically updated by the client library when necessary.

An unknown provider will still be usable - the intention of the known provider list is not to strictly whitelist providers, as this would stifle competition. However, additional user consent will be required upon every interaction with an unknown provider, to ensure the user is aware of the potential risks. Known providers will not have this restriction, and legitimate credential providers will be encouraged to register themselves with the OpenID Foundation to become known providers.

Where possible on each supported platform, the user SHOULD be able to specify their preferred credential provider. This preferred provider will be used exclusively for assisted sign-up and credential saving. For credential retrieval, additional providers MAY still be used.

2.3. Token providers

A token provider is a service that is able to issue an authoritative "proof of access" ID token for an identifier. For example, Google is the token provider for all "gmail.com" email addresses, while Microsoft is the token provider for all "live.com" email addresses.

Token providers are identified by their canonical token-issuing domain, which hosts the token endpoint that provides ID tokens. In the case of Google, this is https://accounts.google.com.

Token providers can be authoritative for a large set of domains or numbers, and there is not often an easy way to determine in advance the token provider for a given domain. OpenYOLO does yet not attempt to solve this particular problem.

2.4. Authentication domains

An authentication domain is defined to be a scope within which a credential is considered to be usable. Authentication domains are represented as absolute, hierarchical URIs of form scheme://authority - no path, query or fragment is permitted.

In protocol buffer form, an authentication domain is represented by the following message:

message AuthenticationDomain {
  // required
  string uri = 1;
}

The URI is encapsulated in a message to allow for future extensibility of the concept of an authentication domain, without altering the structure of containing messages.

Two forms of authentication domain are presently defined:

  • Web authentication domains, which match the domain of the site and can have either a http or https scheme (e.g. https://example.com and http://www.example.com are valid web authentication domains). HTTPS is strongly preferred for use with OpenYOLO, but HTTP is also supported for testing and development purposes.

  • Android authentication domains, of form android://[email protected] where package is the package name of an app (e.g. com.example.app), and fingerprint is a Base64, URL-safe encoding of the app's public key (provided by the Signature type in Android). The fingerprint string includes both the hash algorithm used, and the hash data, e.g. sha512-7fmduHK.... All OpenYOLO credential providers MUST support both sha256 and sha512 as hash algorithms for fingerprints, and MAY support any other hash algorithm that provides equivalent or better security than SHA-256.

An authentication system which validates credentials MAY be represented by multiple distinct authentication domains. For example, a credential for android://[email protected] might be usable on https://example.com or https://www.example.com, when these three entities all use the same authentication system.

An authentication domain equivalence class defines the set of authentication domains associated with a given authentication system, and therefore the places where credentials can be used safely across domains. Such equivalence classes improve the usability of OpenYOLO, but must be carefully defined to avoid compromising the security of a user's credentials. Equivalence classes SHOULD be explicitly defined by the service that owns the associated domains and apps, and SHOULD NOT be assumed or heuristically constructed by the credential provider.

OpenYOLO recommends the use of the Digital Asset Links as a standard mechanism to define authentication domain equivalence classes. Credential providers SHOULD use this information as part of defining the equivalence class over authentication domains. It is the responsibility of the credential provider to correctly construct and utilize the authentication domain equivalence class.

2.5. Authentication methods

An authentication method is a mechanism by which a user credential can be verified, and is given a unique URI identifier. Any URI of form scheme://authority can be used to describe an authentication method. URIs of this form are used to allow for namespacing of custom authentication methods, by using a custom (private) scheme.

In protocol buffer form, authentication methods are represented by the following message:

message AuthenticationMethod {
    // required
    string uri = 1;
}

The URI is encapsulated in a message to allow for future extensibility of the concept of an authentication method, without altering the structure of containing messages.

OpenYOLO defines some standard URIs for the three most common types of authentication methods:

  • Email identifier based authentication. This implies that the primary identifier of the account (from the user's perspective, at least) is their email address. Authentication requires a password or proof of access to the stated email address. The URI for this authentication method is standardized as openyolo://email.

  • Phone number based authentication. This implies that the primary identifier for the account is a phone number, represented to OpenYOLO in E.164 format. Authentication requires a password or proof of access to the stated phone number. The URI for this authentication method is standardized as openyolo://phone.

  • User name and password based authentication. This implies that the primary identifier is some printable unicode string of characters, and that authentication requires a password. The URI for this authentication method is standardized as openyolo://username.

Where a federated credential from an identity provider is desired, the canonical domain of that identity provider SHOULD be used as the authentication method. The canonical domain for an identity provider is the domain that hosts the provider's sign in page. For example, the URI that should be used for Google Sign-in is https://accounts.google.com, while the URI that should be used for Facebook Sign-in accounts is https://www.facebook.com.

Use of consistent authentication method URIs for identity providers is strongly recommended, as this helps with hint retrieval - use of federated credentials on other services can be surfaced more easily when consistent authentication methods are used.

2.6. Password specifications

services that support password based authentication often impose restrictions on what is considered to be a valid password for the service. While the intentions behind these restrictions are often well-meaning, the inconsistency of these restrictions across different services is a source of frustration for both users and credential managers.

When credential managers attempt to generate passwords for a service, they are forced to use a "lowest common denominator" heuristic that produces broadly supported passwords. Even this can fail, requiring the user to modify the generated password.

A better approach is for the service to declare its password restrictions in a format that can be consumed by credential managers. OpenYOLO defines a simple scheme for this, composed of the following pieces of information:

  • The set of allowed characters in a password, which MUST be a subset of the ASCII printable character set.
  • The minimum and maximum length of a password.
  • Zero or more required character sets. A required character set MUST be a subset of the allowed character set, and specify the minimum number of characters from this set that must occur in the password. Where multiple required character sets are defined, the sets MUST be disjoint.

This is represented by the following protocol buffer message:

message PasswordSpecification {
  // required
  string allowed = 1;

  // required
  uint32 min_size = 2;

  // required
  uint32 max_size = 3;

  repeated RequiredCharSet required_sets = 4;
}

message RequiredCharSet {
  // required
  string chars = 1;

  // required
  uint32 count = 2;
}

This allows the expression of most password restrictions. As an example, consider an authentication system that requires passwords be:

  • Composed of any ASCII printable characters
  • Be between 6 and 128 characters long
  • Have at least one upper case character and one number.

This can be defined as follows (with the full contents of the allowed character set abbreviated):

{
  "allowed": "abcdef...",
  "min_size": 6,
  "max_size": 128,
  "required_sets": [
    {
      "chars": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
      "count": 1
    },
    {
      "chars": "1234567890",
      "count": 1
    }
  ]
}

Other common forms of credential, such as PIN numbers, can also be easily defined:

{
  "allowed": "0123456789",
  "min_size": 6,
  "max_size": 6
}

The default password specification used by OpenYOLO, where a provider does not explicitly specify an alternative, is:

{
  "allowed": "abcdefghijkmnopqrstxyzABCDEFGHJKLMNPQRSTXY3456789",
  "min_size": 12,
  "max_size": 16,
  "required_sets": [
    {
      "chars": "abcdefghijkmnopqrstxyz",
      "count": 1
    },
    {
      "chars": "ABCDEFGHJKLMNPQRSTXY",
      "count": 1
    },
    {
      "chars": "3456789",
      "count": 1
    }
  ]
}

This produces passwords of length 12 to 16 based on a "distinguishable" character set. Characters which look similar, such as l (Lima), I (India) and 1 (one) are omitted so as to avoid transcription errors should the user ever have to view and copy a generated password manually. It is designed to be broadly compatible and produce passwords with sufficient entropy to resist offline attacks, but it is still preferable for services to declare their own password restrictions.

It is worth noting that this specification does not support the definition of the following types of password restriction:

  • Positional restrictions, such as "the first character cannot be a number" or "the last two characters cannot be numbers".
  • Semantic restrictions, such as "the password cannot contain an english word" or "the password cannot contain a year".

Such restrictions are either indicative of some anti-pattern in the underlying credential store (e.g. the credential is stored in plain text), or are just too difficult to define a clear specification of expected behavior.

2.7. Client versions

OpenYOLO client libraries will typically be compiled in to service implementations, and therefore cannot be changed without releasing a new version of the service that client devices must download. Bugs are inevitable, and where these bugs impact the security of the client it is important to have a mechanism to protect services from the exploitation of these bugs.

In order to facilitate this, requests sent from a service to a credential provider SHOULD carry a client version descriptor, which is typically compiled into the OpenYOLO client library they are using. This allows a credential provider to identify services which are using an exploitable version of the client library, and to reject requests from these clients.

In OpenYOLO, a client version is composed of:

  • A vendor string, which identifies the author of the client. For the official client libraries shipped by the OpenID Foundation, this will be "openid.net".

  • A major, minor and patch version number. Each are non-negative numbers and typically represented in the human-readable form "X.Y.Z", and follow the general principles of Semantic Versioning.

In order to prevent trivial modification of the client version, it SHOULD be statically compiled in to the client library. There is no way to guarantee that the client version cannot be tampered with by an attacker, however; as such, client versions SHOULD NOT be interpreted as authoritative, and SHOULD NOT be used for purposes other than blacklisting of known problematic client versions only.

In protocol buffer form, a client version is represented by the following message:

message ClientVersion {
  // required
  string vendor = 1;

  // required
  uint32 major = 3;

  // required
  uint32 minor = 4;

  // required
  uint32 patch = 5;
}

An example client version could look like:

{
  "vendor": "openid.net",
  "major": 1,
  "minor": 0,
  "patch": 12
}

3. Operations

OpenYOLO defines four core operations:

A provider MAY implement any subset of these operations; none are required. Each operation is described in more detail in the following sections.

3.1. Hint retrieval

When an service wants to create a new account for the user, they typically need the following core pieces of information:

  • The authentication method that the user prefers to use, drawn from the set that the service supports. For instance, a service might allow a user to create an account with a phone number, Google Sign-in or Facebook Sign-in. If a non-federated authentication method is used, a generated password that conforms to the service's password restrictions is desirable.

  • A unique identifier for the account, which is typically an email address, or phone number that would also be used for account recovery. For many services, proof of access to this identifier is crucial, and so an ID token is also desired to avoid an out-of-context verification.

  • A display name and profile picture for the user, in order to personalize the service. Where it is possible for a user to have multiple accounts with the service, the display name and profile picture help the user to distinguish between these accounts.

The OpenYOLO hint retrieval operation allows a service to request this information from the credential provider. In response, the credential provider is expected to present a choice of the user's commonly-used identifiers or federated credentials, enabling a "single tap" account creation experience. After selection, the provider might return a Credential object representing the user's selection, optionally including a generated password or ID token if applicable. A hint MUST NOT be returned automatically by a credential provider - user interaction is strictly required before any personally identifying information is returned.

Where a proof of access ID token is desired, a service MUST declare the token providers that is supports. Additionally, for each supported token provider, a client ID MAY be required. This is typically a value generated by the token provider during registration as an OAuth2 client. Finally, a nonce can be provided that will be included in any generated ID token, as a protection against replay attacks. Non-standard properties specific to each token provider MAY be specified via an additional properties map.

3.1.1. Hint request message

A hint retrieval request is represented by the following protocol buffer message:

message HintRetrieveRequest {
    ClientVersion client_version = 1;

    // at least one authMethod required
    repeated AuthenticationMethod auth_methods = 2;

    PasswordSpecification password_spec = 3;
    map<string, TokenRequestInfo> supported_token_providers = 4;
    map<string, bytes> additional_props = 5;
}

message TokenRequestInfo {
    string client_id = 1;
    string nonce = 2;
    map<string, bytes> additional_props = 3;
}

A simple hint request could then look like the following:

{
  "auth_methods": [
    "openyolo://email",
    "https://accounts.google.com",
    "https://www.facebook.com"
  ]
}

This indicates that the service supports email and password based authentication, Google Sign-in and Facebook Sign-in. The service has not declared a password specification, therefore the OpenYOLO default specification SHOULD be used by the credential provider if necessary. No supported token providers have been specified, therefore no ID token is desired.

A more complex request, with a custom password specification and two supported token provider could look like:

{
  "auth_methods": [
    "openyolo://email"
  ],
  "password_spec": {
    "allowed": "0123456789",
    "min_size": 6,
    "max_size": 6
  },
  "supported_token_providers": {
    "https://accounts.google.com": {
      "client_id": "CLIENT.apps.googleusercontent.com",
      "nonce": "asdf123"
    },
    "https://auth.example.com": {
      "client_id": "11451",
      "nonce": "asdf123"
    }
  }
}

3.1.2. Hint response message

A hint retrieval response is represented by the following protocol buffer message:

message HintRetrieveResult {
  enum ResultCode {
    UNSPECIFIED = 0;
    BAD_REQUEST = 1;
    HINT_SELECTED = 2;
    NO_HINTS_AVAILABLE = 3;
    USER_REQUESTS_MANUAL_AUTH = 4;
    USER_CANCELED = 5;
  }

  // required
  ResultCode result_code = 1;

  Hint hint = 2;
  map<string, bytes> additional_props = 3;
}

The result codes are defined as follows:

  • UNSPECIFIED: The generic catch-all for a request failure. This SHOULD NOT be used by providers, unless the other defined response codes do not apply.

  • BAD_REQUEST: The request sent by the client was malformed or violated some security constraint enforced by the provider. This error should be treated as permanent; repeating the exact same request should result in the same error code response.

  • HINT_SELECTED: The user selected a hint, which has been returned in the hint field of the message.

  • NO_HINTS_AVAILABLE: No hints are available that match the constraints of the request.

  • USER_REQUESTS_MANUAL_AUTH: The user canceled the selection of a hint in a manner that indicates they wish to proceed with authentication, but by manually entering their details. Providers SHOULD return this code if they display an option like "none of the above" or "use different account" and the user selects it.

  • USER_CANCELED: The user canceled the selection of a hint in a manner that indicates they do not wish to authenticate at this time. Providers SHOULD return this code if:

    • The user presses the back button on their device
    • The user clicks outside the control area of a modal dialog
    • The user chooses some explicit option like "not now".

An email and password credential hint that could be returned for a requesting app "com.example.app" could be:

{
  "result_code": "HINT_SELECTED",
  "hint": {
    "id": "[email protected]",
    "auth_method": "openyolo://email",
    "display_name": "Jack Black",
    "display_picture_uri": "https://www.robohash.org/dcd65581?set=3",
    "generated_password": "YjW5Zvn3Fc7fY",
    "id_token":
        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpX
        VCJ9.eyJzdWIiOiJqZG9lQGdtYWlsLmNv
        bSIsImF1ZCI6Imh0dHBzOi8vbG9naW4uZ
        XhhbXBsZS5jb20iLCJpc3MiOiJodHRwcz
        ovL2F1dGguZXhhbXBsZS5jb20iLCJuYW1
        lIjoiSmFuZSBEb2UifQ.CibuoaNMO-2pR
        QjWUbJMpMLWjKB34AMWCR4pIWD5tnE"
  }
}

Alternatively, a federated credential hint for Google Sign-in might look like:

{
  "result_code": "HINT_SELECTED",
  "hint": {
    "id": "[email protected]",
    "auth_method": "https://accounts.google.com",
    "display_name": "John Doe"
  }
}

3.1.3. Example hint retrieval scenario

Jane Doe is visiting the travel site https://adventures.example.com for the first time. Upon first page load, the site attempts to retrieve an existing credential using OpenYOLO, but nothing is saved so it does not interrupt Jane's flow further at this point.

After browsing a few travel packages, Jane notices a button with label "save for later", and decides to press it. The service navigates to an account creation screen, explaining that an account must be created to save the package. At this point, the service sends a hint retrieval request, and a hint selector dialog is presented:

+------------------------------------+
|                              +---+ |
| Continue With:               | X | |
|                              +---+ |
| +--------------------------------+ |
|                                    |
|  +---+ Jane Doe                    |
|  | O |                             |
|  |/_\| [email protected]              |
|  +---+                             |
|        (with generated password)   |
|                                    |
| +--------------------------------+ |
|                                    |
|  +---+ John Doe                    |
|  | O |                             |
|  |/_\| [email protected]            |
|  +---+                             |
|        (with generated password)   |
|                                    |
| +--------------------------------+ |
|                                    |
|  +---+ Jill Doe                    |
|  | O |                             |
+--+---+-----------------------------+

Jane selects her most commonly used email address; a password is generated and a credential returned to the service, and the provider is able to produce an ID token for the selected email address.

The service utilizes the returned hint to bootstrap the new account, and after successfully creating the account requests that the credential provider save the credential. As the credential has not been modified by the site from the details in the returned hint, it saves the credential automatically.

From Jane's perspective, this all happens from a single click on an account in a presented dialog. She is now signed in, and the travel package she selected is now saved to her account so she can return to it later.

3.2. Credential retrieval

Where an existing credential is known for a service, it is often beneficial to the service and the user for that credential to be retrieved and used for authentication as early as possible. This allows the service to be appropriately personalized to the user, such as providing shopping recommendations based on past purchases. This SHOULD, of course, respect the user's preferences, as there are many legitimate use cases where a user might wish to browse a service in a signed-out state.

3.2.1. Credential request message

A credential retrieval request is represented by the following protocol buffer message:

message CredentialRetrieveRequest {
    ClientVersion client_version = 1;

    // at least one authMethod required
    repeated AuthenticationMethod auth_methods = 2;

    map<string, TokenRequestInfo> supported_token_providers = 3;
    bool require_user_mediation = 4;
    map<string, bytes> additional_props = 5;
}

The service lists the authentication methods that it supports, which are used to filter the set of credentials that are stored by the credential provider. Similar to hint requests, the service can also specify its supported token providers - the return of a valid ID token can provide an additional signal to the service that this login attempt is legitimate.

To prevent automatic sign-in loops, where a user signs out and is inadvertently signed back in again automatically by a credential retrieve request, the require_user_mediation flag can be set to true. If absent from the request message, this is assumed to be false. When true, and one or more credentials are available, the provider MUST require an explicit credential selection from the user, even if only one option is available. This then gives the user the opportunity to more clearly state their intent in an account-switch scenario, by rejecting the presented credential and entering an account creation or manual sign-in flow.

In response to a credential request, the credential provider can either:

  • directly return a credential for automatic sign-in
  • Show a credential picker to the user
  • Return a failure result code if no matching credentials are available.

Automatically returning a credential is optional, and if it is a facility provided by the credential provider, SHOULD be something that the user can disable. A credential SHOULD NOT be returned by a provider unless it believes that the credential is a valid, existing credential for the requesting service.

An example credential retrieval request could look like:

{
  "auth_methods": [
    "openyolo://phone",
    "https://www.facebook.com"
  ]
}

3.2.2. Credential response message

The response to a credential request is represented by the following protocol buffer message:

message CredentialRetrieveResult {
  enum ResultCode {
    UNSPECIFIED = 0;
    BAD_REQUEST = 1;
    CREDENTIAL_SELECTED = 2;
    NO_CREDENTIALS_AVAILABLE = 3;
    USER_REQUESTS_MANUAL_AUTH = 4;
    CANCEL_AUTH = 5;
  }

  // required
  ResultCode result_code = 1;

  Credential credential = 2;
  map<string, bytes> additional_props = 3;
}

The result codes are defined as follows:

  • UNSPECIFIED: The generic catch-all for a request failure. This SHOULD NOT be used by providers, unless the other defined response codes do not apply.

  • BAD_REQUEST: The request sent by the client was malformed or violated some security constraint enforced by the provider. This error should be treated as permanent; repeating the exact same request should result in the same error code response.

  • CREDENTIAL_SELECTED: The user selected a hint, which has been returned in the hint field of the message.

  • NO_CREDENTIALS_AVAILABLE: No credentials are available that match the constraints of the request.

  • USER_REQUESTS_MANUAL_AUTH: The user canceled the selection of a hint in a manner that indicates they wish to proceed with authentication, but by manually entering their details. Providers SHOULD return this code if they display an option like "none of the above" or "use different account" and the user selects it.

  • USER_CANCELED: The user canceled the selection of a hint in a manner that indicates they do not wish to authenticate at this time. Providers SHOULD return this code if:

    • The user presses the back button on their device
    • The user clicks outside the control area of a modal dialog
    • The user chooses some explicit option like "not now".

An example response could therefore look like:

{
  "result_code": "CREDENTIAL_SELECTED",
  "credential": {
    "id": "jdoe",
    "auth_domain": "https://login.example.com",
    "auth_method": "https://www.facebook.com"
  }
}

Or, if the user was presented a list of credentials and did not select one:

{
  "result_code": "USER_CANCELED"
}

3.2.3. Example credential retrieval scenario

Jane has just bought a new phone and has just installed the "TechNews" app. When she opens the app, it immediately sends a credential retrieval request for email, Google and Facebook stored credentials. Jane frequently used TechNews on her old phone and had saved his email address and password with her credential provider. Her credential provider receives the request, and automatically returns the saved credential to the TechNews app and displays a notification that it has done so. The TechNews app uses the credential to sign in, and shows Jane her personalized feed of news.

3.3. Credential saving

Once a user has created an account or successfully signed in using an existing account, it is beneficial to them for this credential to be saved to their credential provider. This ensures that when the user changes device, or their session is invalidated, re-authentication is simplified through the use of the credential retrieval operation.

In the case where a service saves a credential that is already known, this is still a useful signal to the credential provider that the saved data is accurate. Where discrepancies are detected, such as a change in password, this provides an opportunity to confirm and update the saved data. Credential providers MAY allow automatic saving of credentials, but it is recommended to seek explicit confirmation from the user where the credential data is new or sensitive (i.e. contains a previously unseen identifier or password).

How this confirmation is solicited from the user is outside the scope of this specification; the reference implementation uses the following confirmation dialog style design:

+------------------------------------+
|                                    |
| Save your password for ExampleApp  |
|         to ExampleProvider?        |
|                                    |
|    +----+ +--------------------+   |
|    | OK | | Never for this app |   |
|    +----+ +--------------------+   |
|                                    |
+------------------------------------+

3.3.1. Save request message

A save credential request is represented by the following protocol buffer message:

message CredentialSaveRequest {
    ClientVersion client_version = 1;

    // required
    Credential credential = 2;

    map<string, bytes> additional_props = 3;
}

3.3.2. Save response message

message CredentialSaveResult {

  enum ResultCode {
    UNSPECIFIED = 0;
    BAD_REQUEST = 1;
    SAVED = 2;
    PROVIDER_REFUSED = 3;
    USER_CANCELED = 4;
    USER_REFUSED = 5;
  }

  // required
  ResultCode result_code = 1;

  map<string, bytes> additional_props = 2;
}

The result codes are defined as follows:

  • UNSPECIFIED: The generic catch-all for a request failure. This SHOULD NOT be used by providers, unless the other defined response codes do not apply.

  • BAD_REQUEST: The request sent by the client was malformed or violated some security constraint enforced by the provider. This error should be treated as permanent; repeating the exact same request should result in the same error code response.

  • SAVED: The credential was saved, or an equivalent credential was updated.

  • PROVIDER_REFUSED: The provider refused to save the credential, due to some policy restriction. For example, a provider may refuse to update an existing credential if it is stored in a shared keychain. The client SHOULD NOT request to save this credential again.

  • USER_CANCELED: The user dismissed the request to save the credential, by either pressing the back button, clicking outside the area of a modal dialog, or some other "soft" cancelation that is not an explicit refusal to delete the credential. The client MAY request to save this credential again at a later time.

  • USER_REFUSED: The user refused the request to save this credential. The client SHOULD NOT request to save this credential again.

3.4. Credential deletion

Stale credentials stored in a credential provider are a source of frustration for users. Stale credentials are particularly common in browsers that rely on heuristics to detect password changes and update saved credentials.

When a credential is stale, it only serves as a barrier to authentication. In most cases, the user will be forced to perform a tedious account recovery process, and if they do not remember to manually delete the stale credential, will likely be faced with the same issue again in the future.

In order to provide services a way to flag stale credentials to a provider, a credential deletion operation is defined. Credential providers SHOULD NOT allow automatic deletion of credentials, as this would allow misbehaving services to delete valid credentials. Financial institutions are notorious for these kinds of user-hostile policies, and might attempt to delete valid credentials as a misguided way to "protect" the user. As such, credential deletion SHOULD require explicit user confirmation. Where this is done legitimately, such as after a retrieved credential is discovered to be invalid or a user deletes their account, the request for confirmation will not be surprising to the user.

3.4.1. Delete request message

A credential deletion request is represented by the following protocol buffer message:

message CredentialDeleteRequest {
    ClientVersion client_version = 1;

    // required
    Credential credential = 2;

    map<string, bytes> additional_props = 3;
}

3.4.2. Delete response message

A credential deletion response is represented by the following protocol buffer message:

message CredentialDeleteResult {
  enum ResultCode {
    UNSPECIFIED = 0;
    BAD_REQUEST = 1;
    DELETED = 2;
    NO_MATCHING_CREDENTIAL = 3;
    PROVIDER_REFUSED = 4;
    USER_CANCELED = 5;
    USER_REFUSED = 6;
  }

  // required
  ResultCode result_code = 1;

  map<string, bytes> additional_props = 2;
}

The result codes are defined as follows:

  • UNSPECIFIED: The generic catch-all for a request failure. This SHOULD NOT be used by providers, unless the other defined response codes do not apply.

  • BAD_REQUEST: The request sent by the client was malformed or violated some security constraint enforced by the provider. This error should be treated as permanent; repeating the exact same request should result in the same error code response.

  • DELETED: The credential was deleted.

  • NO_MATCHING_CREDENTIAL: The credential was not deleted, as there was no matching credential to delete.

  • PROVIDER_REFUSED: The provider refused to delete the provided credential, due to some policy restriction it is enforcing. For example, a provider could refuse to delete a credential from a shared keychain. The client SHOULD NOT request to delete this credential again.

  • USER_CANCELED: The user dismissed the request to delete the credential, by either pressing the back button, clicking outside the area of a modal dialog, or some other "soft" cancelation that is not an explicit refusal to delete the credential. The client MAY request to delete this credential again at a later time.

  • USER_REFUSED: The user explicitly refused to delete the credential, by selecting a "do not delete" (or similarly phrased) option in the presented UI. The client SHOULD NOT request to delete this credential again.

The OpenYOLO protocol is implemented on Web by opening a hidden iframe for a credential manager, and establishing a message channel with it to exchange protocol messages. Through this approach, no browser plugins are required, and the credential provider can be displayed in-context simply by making the hidden iframe visible.

Securing the OpenYOLO protocol on the web is significantly more difficult than on Android, but the reward for doing so is ubiquity: OpenYOLO Web can be used on virtually all platforms, and is a viable approach to authenticating on iOS through the use of a SFSafariViewController.


4. Request origin verification


Author's Address

Iain McGinniss
Google, Inc.
1600 Amphitheater Parkway
Mountain View, California 95134
United States of America
Phone: +1-650-253-0000
EMail: [email protected]