Skip to content

Explainer: WebAuthn immediate mediation

Adem edited this page Jan 24, 2025 · 3 revisions

Author

Adem Derinel <[email protected]>

Ken Buchanan <[email protected]>

Last updated: 24-Jan-2025

Summary

We propose an “immediate” mediation modality for WebAuthn and password get() requests which mirrors the preferImmediatelyAvailable API properties on Android and iOS, in response to requests from sites. This modality fails promptly if no credentials are immediately available, and thus allows sites to direct users to fallback sign-in methods in that case.

Background

WebAuthn currently provides two UI flows for sign-in:

  • Modal: browser UI always appears. The returned promise resolves when the user exercises a credential or dismisses the UI.
  • Conditional: browser UI may appear, typically integrated with autofill on a text box. The returned promise only resolves if the user exercises a credential.

The preferImmediatelyAvailable option on mobile platforms provides a lower-friction flow when there is an eligible credential. In that case it immediately displays UI containing available credentials, but if no credential is available then it returns an error so that the calling application can provide alternative sign-in methods. This is similar to conditional UI on the web, but in that case the relying party does not learn whether a credential is available and therefore has to provide all sign-in options on a single surface.

For a site where only a fraction of users have WebAuthn credentials (which is overwhelmingly common, for now), WebAuthn has no great answer for sites which want to implement a “Sign-in” button. We ultimately also want to design an API to help realize the original design of Credential Management and support sites making get() requests that accept credentials of any of several supported types, including WebAuthn, passwords, and federation.

Current modal WebAuthn flow for a user with no local WebAuthn credentials. Whether it is the modal flow or the conditional flow, this may result in offering hybrid flow to the user.

Current modal WebAuthn flow for a user with no local WebAuthn credentials. Whether it is the modal flow or the conditional flow, this may result in offering hybrid flow to the user.

API

We propose a mediation type, immediate for navigator.credentials.get().

When such an option is set, the returned promise resolves with NotFoundError when there are no locally-available credentials; otherwise, the browser handles the authentication ceremony as if there were no mediation property set. Browsers are always free to return NotFoundError if they see fit. (See Privacy section, below.)

try {
  const cred = await navigator.credentials.get({
    publicKey: {
      challenge: ...,
      rpId: 'example.com',
      allowCredentials: [],
    },
    mediation: 'immediate'
  });
} catch (error) {  
  if (error.name === 'NotFoundError') {
    // handle the no credential case
  } else {
    // other cases
  }
} 

Supporting cross-device authenticators

This API risks disadvantaging users of security keys, and those who wish to keep credentials on their mobile device. We note that:

  1. If a security key supports credential enumeration, as in newer CTAP drafts, those credentials can be considered to be immediately available.
  2. Sites will have to support another way to use WebAuthn credentials because, as noted in the Privacy section, we expect this API to always fail in Incognito/private browsing contexts.

Other credential types

On supported browsers, password credentials (i.e. navigator.credentials.get({password: true})) return immediately when there are no passwords available.

Federated credentials and passwords can also support immediate mediation if needed to make a more coherent sign-in flow. With the increased support, relying parties can choose which credential type they want to use as the “primary” sign-in flow and implement the follow-up authentication methods as backup.

While not addressed in this explainer, a future direction of requesting WebAuthn, federated and password credentials together could look like

try {
  const cred = await navigator.credentials.get({
    publicKey: {
      challenge: ...,
      rpId: 'example.com',
      allowCredentials: [],
    },
    identity: { ... },
    password: true,
    mediation: "immediate"
  });
  // Site will also show a button to trigger a modal flow
  // to handle Incognito and security key users
} catch (error) {  
  if (error.name === 'NotFoundError') {
    // No immediate WebAuthn, federated or password credentials found.
    // The relying party can fallback to their preferred solution such as
    // asking the user's phone number / email.
  } 
}

Example use cases

Consider a relying party with an existing user base. They want to use a passkey as easily as possible for users that have them, but users that don’t have passkeys should see the standard sign-in UI.

The relying party’s goal is to provide a frictionless sign-in experience, minimizing confusion and unnecessary steps. They want to avoid overwhelming users with multiple sign-in options, especially those unfamiliar with passkeys.

Here's how the relying party could use the new API to achieve this:

  1. User navigates to the main page of the website (e.g. a shopping page).
  2. Upon page load, and after a user gesture (such as clicking a "Sign In" button), the relying party calls navigator.credentials.get with a PublicKeyCredentialRequestOptions object and mediation: ”immediate”. They may also include password: true in the request.
  3. The browser checks the local authenticators for any local credentials. Ideally, this would be near-instantaneous.
  4. If there are no local credentials
    1. The browser throws a NotFoundError to the relying party.
    2. The relying party asks the user for more details (e.g. email address)
    3. The relying party shows the alternative authentication mechanisms such as a password form, SMS OTP, or the WebAuthn hybrid flow. They can also offer to create a passwordless account if the user details are not in their system.
  5. Otherwise (if there are local credentials):
    1. The browser presents the required UI to the user for authentication.

Example flows: If there are WebAuthn credentials (or passwords) locally, browser UI will prompt the user to select one. The user can choose another way in the browser UI to fallback to the sign-in / sign-up page. In the case of no WebAuthn credentials locally, the website should show the existing sign-in / sign-up page.) Example flows: If there are WebAuthn credentials (or passwords) locally, browser UI will prompt the user to select one. The user can choose another way in the browser UI to fallback to the sign-in / sign-up page. In the case of no WebAuthn credentials locally, the website should show the existing sign-in / sign-up page.

Privacy considerations

Currently the RP does not have a way to learn about the availability of WebAuthn credentials until the user interacts with browser API, authorizing the generation of an assertion. Under this proposal that would change, enabling the RP to learn about the presence of immediately available credentials without such an authorization. It would not learn any information about the credentials until the assertion is returned, but the single bit available from the API returning a NotFoundError or not represents a relaxation of WebAuthn privacy protections.

We propose the following measures to mitigate the potential for abuse of that relaxation:

User gesture requirement

To mitigate silent probing of credential availability and fingerprinting, we are considering requiring a user gesture before this API call can be made. This user gesture can be a button click and we seek feedback from sites on this.

Incognito and private sessions

In incognito or private sessions, any immediate mediation request should throw NotFoundError. To avoid incognito fingerprinting, this response can be randomly delayed by the browser to simulate the browser fetching credential metadata from the system.

Request with allowlists

Requests with allowlists should throw NotAllowedError. If a relying party queries for a list of credentials and gets a response indicating one exists, this could be used to infer whether the user has previously interacted with the site. Over time, this could allow tracking of users across different sessions.

Cancelation

Setting the signal parameter on a request with immediate mediation is invalid as sites should not be able to programmatically dismiss any browser UI.

Multi RP ID probing

A site could register every user on a unique subdomain then, using immediate mediation, probe every possible subdomain to find the identity of an unknown user. This is not terribly practical, and the user will ultimately see browser UI, but it is a concern. If implemented, a user gesture requirement would make this implausible. Otherwise some form of rate-limiting will be needed.

Similar systems

Both Android and iOS APIs support immediately available credential calls for sign in. Android Credential Manager will respond with NoCredentialException similar to NotFoundError DOMException when the sign in request prefers immediately available credentials but none are available.