w3c / webauthn

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

Add support for hinting at verbiage other than "sign in" during authentication #2086

Open Firehed opened 3 months ago

Firehed commented 3 months ago

Description

Currently, there's no way to influence the text shown to users during authentication, beyond the previously-registered name values. For the common case of signing in, the default text provided by user-agents is generally fine and appropriate. However, as WebAuthn and passkeys become more widely deployed, there are additional scenarios where users may be prompted to (re)authenticate where the common "sign in"[^1] text displayed isn't very appropriate.

In order to reduce user confusion in these scenarios, being able to better control the contents of the dialog displayed would be beneficial.

This could perhaps be an enhancement to the existing PublicKeyCredentialHints, or a similar additional (optional) structure, defaulting to the current behavior when omitted.

Some use-cases that aren't well served by the existing text and could be enhanced:

Even being able to be consistent with a website's existing text ("log in" vs "sign in"), though not nearly as useful as updating the text for actions that aren't actually signing in. Being able to provide free-form text is not something I'd advocate for (yet), but a half-dozen or so predefined enum values could go a long way here.

None of this would change the actual authentication process or data; it's intended solely as a UX improvement to clarify to the end-user the result of using their passkey.

enum PublicKeyCredentialInterfaceHints {
    "sign-in",
    "log-in",
    "pay",
    "subscribe",
    "confirm"
};

UI concept if the pay hint were used: passkey-confirm-payment-mock

Specifically in the payment area, I don't think the complexity of providing amounts to display in the dialog is worthwhile - it adds a lot of burden to all parties involved since it would invite stuff like "Subscribe for $6/wk for two months then $10/wk thereafter"

If this is a concept that people want to move forward with, I'd be more than happy to draft up the change more formally.

Related Links

This has been on the back of my mind for a while, and resurfaced thanks to #2084.

[^1]: The current text already varies quite a bit by OS and browser

Kieun commented 3 months ago

This issue is already discussed in this WG (#1823) and I would like to support this issue and hope to leverage similar features to offer better UX.

emlun commented 3 months ago

Yes, this seems like a duplicate of #1823.

For the payment use case specifically, there is Secure Payment Confirmation which is an alternate API building on top of WebAuthn.

lgarron commented 3 months ago

Yes, this seems like a duplicate of #1823.

That issue is closed, and this issue offers a bit more of a concrete proposal. I think the list from @Firehed above is a very pragmatic starting place for real-world RPs:

enum PublicKeyCredentialInterfaceHints {
    "sign-in",
    "log-in",
    "pay",
    "subscribe",
    "confirm"
};

If this issue is closed, could we ask for #1823 to be opened instead of dropping the topic from this repo?

Firehed commented 3 months ago

@emlun SPC looks like an excellent API to handle the more complex use-cases - thanks for sharing that!

Until browser support for that API improves, I suspect that RPs may use WebAuthn as it exists today for incremental progress towards the same goal even if they evolve to support SPC over time.

In any case, I don't want to over-index on the payment use-case since WebAuthn is valuable for many other situations. For example, I suspect a lot of folks here have used it in Github settings screens to re-authenticate an active session prior to a sensitive action (adding an SSH key, changing email, etc).

To expand on the proposed specifics a bit:

const credential = await navigator.credentials.get({
  publicKey: {
    // ...
    displayHints: ['value-in-discussion', 'confirm', 'sign-in'],
  },
})

This would follow the same semantics of the existing hints field - send in order of specificity/importance. Unknown/unsupported values would be ignored by browsers, and the first understood value could be used to adjust the UI, falling back to the current behavior if none are known or provided.

Or for a more streamlined version, it could extend the existing PublicKeyCredentialHints enumeration and build on the existing semantics described in §5.1.4 step 18:

const credential = await navigator.credentials.get({
  publicKey: {
    // ...
    hints: ['security-key', 'confirm'],
  },
})

This would represent prompting for a physical security key to confirm an action rather than signing in, and the user-agent could adjust the UI accordingly. Since the existing semantics of Enum-as-DOMString (§2.1.1) says to "handle" unknown values and the hints are provided in order of decreasing preference, this would allow RPs to provide both the transport hints and dialog texts in the same place.

There's pros and cons to extending hints vs having a separate enumeration and options key, though based on my read of the currently published L3 spec, I think extending hints may provide the least overall friction to most RPs (and, likely, the least amount of change to the spec itself). I'd like to hear more from browser vendors on this one; it seems similar to how e.g. autocomplete tokens are parsed for <input> elements (notably the webauthn token) since they're at times overloaded for multiple somewhat-orthogonal ideas.

timcappalli commented 3 months ago

Not opposed to this, but I think we should defer discussions to L4 based on existing work items, priorities, and the number of parties this impacts (it's not just browsers).

/cc @nadalin