w3c / webauthn

Web Authentication: An API for accessing Public Key Credentials
https://w3c.github.io/webauthn/
Other
1.18k stars 171 forks source link

Allow Conditional Mediation without autofill #2144

Open kenrb opened 1 month ago

kenrb commented 1 month ago

This is not intended for level 3.

Proposed Change

I have added an explainer to the wiki proposing a new UI mechanism and a way for sites to trigger it. The motivation is to provide conditional UI functionality that is not tied to autofill, so it can be used to sign in to an RP without necessarily being on a dedicated sign-in page.

As with existing conditional UI, the user agent would ignore the request if there are no eligible credentials for the current RP.

At Google we have been tentatively labeling this "ambient UI", reflecting that we are imagining an unobtrusive non-modal UI surface that can be ignored by the user.

sbweeden commented 1 month ago

Would it be reasonable to suggest this is loosely akin to the FedCM experience?

agl commented 1 month ago

Would it be reasonable to suggest this is loosely akin to the FedCM experience?

Yes, albeit with the important qualifier that this would only appear if the user has existing credentials for the site. It would not appear otherwise, while FedCM can.

MasterKale commented 1 month ago

Is there a desire to support display of both the autofill UI as well as "ambient" UI at the same time? If it would be best for this to be either/or, what if an RP opted into ambient display by omitting the autocomplete tokens that are currently required in L3? 🤔

Screenshot 2024-09-10 at 4 55 16 PM

https://w3c.github.io/webauthn/#GetAssn-ConditionalMediation-Interact-FormControl

That is to say, if an RP doesn't specify autocomplete tokens to indicate explicitly where the conditional UI should be displayed, then e.g. "the user agent is free to choose how to display relevant UI to initiate an authentication ceremony"

agl commented 1 month ago

That is to say, if an RP doesn't specify autocomplete tokens to indicate explicitly where the conditional UI should be displayed, then e.g. "the user agent is free to choose how to display relevant UI to initiate an authentication ceremony"

I would worry about races where the DOM elements are constructed by Javascript after page load, but the browser has already looked and decided that there weren't any.

emlun commented 1 month ago

This proposes a new field be added to PublicKeyCredentialRequestOptions. The field is called display, and initially has two values: autofill and ambient. When unspecified, its default value is used, which is autofill.

Setting the display field in a request that does not specify conditional mediation results in an error.

Related to @MasterKale's comment: I agree this seems like this would be better expressed as new mediation option value that is mutually exclusive with mediation: "conditional". For example, mediation: "ambient". Since mediation: undefined, display: "ambient" is an error, the API would be better if that combination is impossible in the first place. Would that work?

One possible issue could be that this might interfere with the last paragraph:

If the site wants to have the Ambient UI prompt and also has a sign-in form on that page, the autofill behavior still works. That is, on a request with display: ‘ambient’ if the user dismisses or ignores that UI but then clicks on a webauthn-tagged input field, the autofill UI will show the same as for a display: ‘autofill’ request.

But maybe that could be addressed by calling the option value something like mediation: "conditional-ambient", to make it clearer that this is an "extension" of conditional medation?

kenrb commented 1 month ago

Related to @MasterKale's comment: I agree this seems like this would be better expressed as new mediation option value that is mutually exclusive with mediation: "conditional". For example, mediation: "ambient". Since mediation: undefined, display: "ambient" is an error, the API would be better if that combination is impossible in the first place. Would that work?

I was preferring to add it to PublicKeyCredentialRequestOptions rather than adding it to mediation because it doesn't have any meaning for other credential types, and adding it to the Credential Management API is a heavier lift. The current definition of conditional mediation has the attribute defined in CM and the autofill integration defined in WebAuthn, so it also seems appropriate that overriding the latter part could be localized here.

For your concern about clarity, would it help if the new field was named conditional-display?

emlun commented 1 month ago

it doesn't have any meaning for other credential types

Hm, is that because mediation: "conditional" already covers the "ambient" use case for those other types? I.e., the other types don't need the user to interact with an appropriately annotated form control?

For your concern about clarity, would it help if the new field was named conditional-display?

No need, the clarity concern was specifically about mediation: "ambient". display: "ambient" is fine if we're going with having the field on PublicKeyCredentialRequestOptions.

nsatragno commented 1 month ago

I don't think mediation is the right place for this. If I got to redo autofill UI, I would avoid leveraging the mediation parameter for conditional as well. It turns out that conditional (and say a hypothetical ambient) mediation just doesn't make a lot of sense for other credential types, which never adopted it.

Firehed commented 1 month ago

RP perspective: Agreed @nsatragno, and I'll add that a new mediation option is going to add a lot of complexity on the implementing site side as well - more feature detection and conditionally setting the value based on the results (which could expand to the backend depending on setup, not just pure client code). It would be really easy to break an auth flow if you don't get it just right.

Adding a field into the PK dictionary seems sensible - though I'll suggest making it an array of preferences rather than a single value, and browsers should use the first supported entry, and fall back to their current behavior (based on mediation) on no match. This is similar to several other hints.

e.g. you might want to express "use autofill if the correct input element exists, otherwise show the ambient display" (or vice-versa)

{
  "rp": {
    "id": "exmple.com",
  },
  "display": ["autofill", "ambient"], // "modal" too?
  // ...
}

While I doubt there are a whole lot of other potential UIs to consider, if others are added in the future, you can safely add the value in the list and not worry about breaking other flows in browsers that don't yet support it.

It might also be worth going down the list-of-objects path here (instead of list-of-strings) in case there are display customizations that these could support: display: [{"mode": "ambient", "background": "#001122"}, {"mode": "autofill"}]. I'm not personally a huge fan of these types of customizations, but I've had to reinvent a lot of wheels over my career to support them anyway - so getting ahead of it structurally might be worth considering.

For what it's worth, I also like @MasterKale 's suggestion of "just leave off the autocomplete details and let the browser decide" which is delightfully simple on the RP side (but yes, data races)

pascoej commented 1 month ago

<input type="hidden" autocomplete="... webauthn"></input> might be an option.

kenrb commented 1 month ago

<input type="hidden" autocomplete="... webauthn"></input> might be an option.

@pascoej Are you suggesting that RPs could add this to pages in order to get conditional UI on arbitrary pages, without any changes to the spec?

I'd be concerned that having autofill UI appear without visible input fields would be confusing to users. Chrome won't trigger autofill on a hidden field, and I think we'd be reluctant to consider changing that behaviour.

MasterKale commented 1 month ago

@kenrb I took @pascoej's suggestion as a new way to set up a <form> along the lines of how you trigger conditional UI:

<!-- Regular Conditional UI -->
<form action="">
  <input type="email" name="email" id="email" />
  <input type="password" name="password" id="password" autocomplete="current-password webauthn">
</form>

But the presence of type="hidden" input with autocomplete="... webauthn" would trigger the "ambient" UI instead:

<!-- New "Ambient" UI -->
<form action="">
  <input type="email" name="email" id="email" />
  <input type="password" name="password" id="password" autocomplete="current-password">
  <input type="hidden" autocomplete="webauthn">
</form>

Then I'd assume the exact same call to WebAuthn would get a response the same way:

navigator.credentials.get({
  mediation: 'conditional',
  publicKey,
}).then(handleWebAuthnResp);
kenrb commented 1 month ago

I see, thanks for the clarification.

What is the rationale for that? Is it easier for sites to add an element to the HTML than a field to the credential options?

For implementers it would add some complexity, since the JS call handler won't know right away whether it will need to show the ambient UI, and we have to think about handling situations where that element is added to the document at an arbitrary point after page load.

gioele-antoci commented 1 month ago

Couple of questions on this:

  1. In relation to this issue, how would this behave in the cases where password manager monkeyPatch navigator.credentials.get? I imagine the UI would clash? Or more specifically, the password manager's UI would prevail over the ambient UI?
  2. What would the UI look like if the assertion happened from within a (x-domain) iframe?
agl commented 1 month ago

Or more specifically, the password manager's UI would prevail over the ambient UI?

If an extension hooked get() then it must also hook getClientCapabilities(). If it didn't support this interface, it wouldn't advertise support. Thus this UI wouldn't appear.

What would the UI look like if the assertion happened from within a (x-domain) iframe?

Still an open question. Since cross-domain iframes need to be given explicit permission to call WebAuthn by the parent frame, it might be reasonable to allow this. (I.e. perhaps some 3rd-party authentication service would work like that.) But I can also see the argument that the UI is linked to the main frame and thus shouldn't apply in that case.

gioele-antoci commented 1 month ago

Appreciate the clarifications! From Shopify's unique perspective, being able to trigger ambientUI in the top frame from a x-domain iframe would be key to take advantage of this proposed feature

Firehed commented 1 month ago

What is the rationale for that? Is it easier for sites to add an element to the HTML than a field to the credential options?

Forgetting the current autocomplete=webauthn token is a common failure case for using conditional mediation, especially during early development.

Thinking on it more, I'd suggest simplifying this whole concept further, and default to the proposed ambient UI for all conditional requests unless the input field is present (in which case it'll use the existing UIs that are attached to the input field). A well-formed call to credentials.get() signals pretty clear intent to do something relating to authn, and while I broadly prefer explicit over implicit behaviors, this feels like it may be the lowest-friction forward-compatible approach - and shouldn't cause issues for any existing (working) implementations.

For implementers it would add some complexity, since the JS call handler won't know right away whether it will need to show the ambient UI, and we have to think about handling situations where that element is added to the document at an arbitrary point after page load.

I could see the possibility of hiding the ambient UI and switching to the autofill one if an appropriate input autocomplete=webauthn element shows up in the DOM, but I think the majority case is "just show something so the user can sign in" so even that may not be necessary.