Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support a "create or get [or replace]" credential re-association operation #1568

Open
lgarron opened this issue Feb 9, 2021 · 16 comments
Open
Assignees
Labels
@Risk Items that are at risk for L3 type:technical

Comments

@lgarron
Copy link
Contributor

lgarron commented Feb 9, 2021

Proposal

I would like to propose the addition of a way for an RP ask the browser to:

  • Show a create-style prompt the user to create a new credential (matching certain selection criteria), if possible.
  • Otherwise, show a get-style prompt for the user to authenticate using an existing credential matching those criteria, if possible.

In essence: "create or get", where "or" has the same meaning as in most programming languages (take the second branch if the first was unsuccessful). This could be implemented as:

  • An option for create (indicating to use its excludeCredentials as allowCredentials for the get fallback, along with the same selection criteria).
  • A new API call in addition to create and get.

Note that there are situations where the site is trying to ensure that they end up with a credential that matches certain criteria (e.g. discoverable credential, or platform authenticator) but does not know exactly which existing registrations match those criteria (i.e. if the RP cannot tell because some of those registrations were created with different selection criteria). In this case, it's valuable for the selection criteria to filter the get-style prompt.

(Perhaps "get or create" might make more sense, or maybe it could be useful to give the RP the choice of preference between the operations. In any case, the overall idea is similar.)


Motivation

I originally asked about this #1533 and I felt like it was closed quickly because this was an intentional omission of the spec. However, after a lot of work on GitHub's WebAuthn implementation, and several dozen emails with browser authors, it seems that there is still a fundamental issue with authenticators that are shared across multiple browser profiles (as is the case with Windows Hello):

  • It is impossible for the RP to tell if the user has an existing registration or not.
    • If the RP always prompts the user to create a new credential in a fresh browser session, the expected user experience is that the user encounters an error. This sounds pretty undesirable to me.
    • If the RP offers UI with buttons for both "create" and "get", then they are making their registration flow needlessly complicated for new device registrants. This also puts responsibility on the user to remember on which sites/devices/browsers they have signed in before, which seems counter to goals of folks working on WebAuthn. It also requires sites to put in extra engineering effort to handle both cases where the user picked the wrong choice of "create" or "get".

Note that:

  • Some browsers create discoverable credentials even if the RP does not ask for it.
    • In particular, this means that they may create credentials in a way that invalidates previous registrations for the same RP, even if the RP did not ask for this. (Safari and Windows Hello both do this at the moment.)
  • RPs may not want to use discoverable credential auth at the time they first start creating discoverable credentials. They may set residentKey: "preferred" but initially only use the credentials as if they were server-side.
  • As far as I know, there are no browsers that currently allow users to manage registrations. Registrations remain forever (unless evicted by new registrations, in some browsers).
  • It is currently hard to tell if a create call failed due to an existing registration: Can RPs assume that InvalidStateError for create() means an excludeCredentials match? #1566

This puts a wrench in certain hacky workarounds, like using a different user handle for each browser session (which not only seems contrary to the intention of the user handle, but can result in a ballooning set of redundant registrations if discoverable credentials are created).

It can also cause issues with sites that have existing registrations for security keys, and want them to keep working while adding support for passwordless flows: #1569


I'd argue that the benefits of a "create or get" operation like this outweigh the complexity or security implications. It would allow RPs to:

  • Check for isUserVerifyingPlatformAuthenticatorAvailable()
  • If true, show a simple prompt saying "would you like to use your device's built-in authenticator to sign in to this site?"

To me, it seems that this would support the priority of constituencies better than only supporting create or get in the spec.

(EDIT: I flipped the "get" and "create" order after reading @equalsJeffH's comment at #1567 (comment) , since most sites would probably prefer the get path over creating additional credentials..)

@lgarron
Copy link
Contributor Author

lgarron commented Feb 9, 2021

create/get/replace

In the main comment I've only mentioned "create or get". The issue title also includes "replace".

GitHub is in a situation where we've been encouraging users to register platform authenticators as security keys. Since it is impossible to tell if an existing registration (or new registration where the RP did not require a platform authenticator) is for a platform authenticator, we don't know which security keys can be used as platform authenticators.

Because of the current behaviour of Windows Hello and Safari, we need to avoid registering a platform authenticator as both a security key and a trusted device.

So we need a flow where a user can "create or get" a trusted device, but also needs to remove a security key registration if it needs to be re-registered as a user-verifying platform authenticator. In that case, it would be useful to:

  • Specify that the browser should "create" if the matching excludeCredentials entry does not satisfy the selection criteria.
  • Return the new registration, as well as any matching excludeCredentials registrations that were deleted by the platform authenticator as a result of the new registration.

However, I recognize that this is somewhat more complicated. We would also not need it for GitHub if the spec could guarantee that new credentials will only invalidate existing credentials (i.e. only overwrite the [RP, user handle] key in the credential store) that the RP created without specifying a required/preferred resident key at the time.

EDIT: I've filed #1569 to see if it's worth tackling the Windows Hello/Safari behaviour.

@lgarron lgarron changed the title Support a "create/get/replace" credential re-association operation Support a "create or get [or replace]" credential re-association operation Feb 9, 2021
@Kieun
Copy link
Member

Kieun commented Feb 9, 2021

As far as I know, there are no browsers that currently allow users to manage registrations. All the registrations remain forever.

For this, in case of Chrome (maybe Edge as well), you can manage security keys.
chrome://settings/securityKeys
But I'm not sure how much of users know this settings when they are using security keys.

I'm agree with this concerns when deploying WebAuthn to large number of customers. If the WebAuthn is mature, the browsers behave same and users are well educated, we can go with username-less flow with resident key no matter of the authenticator attachment. E.g., RP just presents a button saying "authenticate with trusted device". If there is a user session or similar one, RP might leverage that hint for better usability.

At this stage, RP might try to go with password-less flow by asking username first (if there is no hint on the browser side) and then prompt authentication with credential Ids. Depending on the authentication response, RP might ask further authentication factor to meet their security requirements.
But, if the RP's ultimate goal is username-less flow, RPs should decide the policy whether they allow non-resident key, non-user-verifying security key from the beginning, although these authenticators eventually are now allowed at some point.

@akshayku
Copy link
Contributor

The problem is around the existing platforms which are going to be there for a long time. Also, intention during credential creation should be create it if such a credential for that user does not exist. If a credential exist, InvalidStateError seems like a perfect response to the caller. RP should give all the credentialID to the authenticator during authentication if it is following with-username flows.

@equalsJeffH
Copy link
Contributor

this may be realted to issue #1545 "add support for non-modal UI"

@equalsJeffH
Copy link
Contributor

on 2021-02-10 call:
map to L3. noted that a underlying motivation for this is the present lack of Android support for discoverable creds.

@lgarron
Copy link
Contributor Author

lgarron commented Feb 19, 2021

on 2021-02-10 call:
map to L3. noted that a underlying motivation for this is the present lack of Android support for discoverable creds.

I'd like to clarify that this is mostly orthogonal, as far as I'm concerned.

The main issue here is figuring out how to ensure that a new browser profile can get an associated registration for an RP while keeping the process as straightforward as possible for the user (i.e. by handling it all in a single prompt, if possible). Until something like #1545 becomes available, there is no way for the RPs to do anything without potential situations where a prompt is guaranteed to lead to an error even in the "happy path".

This is already an issue for authenticators/browsers that support discoverable credentials (notably, Safari and Windows Hello). Discoverable credentials in Android would be very welcome, but would not directly help with this issue.

I realized recently that a potential point of confusion is that we want GitHub to support UVPA trusted devices for users without "normal 2FA". My comment here might help clarify some things: #1566 (comment)

@eldanb
Copy link

eldanb commented Jun 15, 2021

Pointing out that the need for "get or create" becomes even more critical with platforms now starting to support platform authenticators that are synchronized between devices (eg Apple's announcements in WWDC21) as well as more and more platforms supporting cross-browser platform authenticators and/or native app authenticators shared with browsers (e.g iOS 14.5).

Many RPs are bringing this up as a barrier to adopting a platform-authenticator, username-less flow.

A "get or create" operation could also offer to the user, in one prompt, to either choose an existing credential or register a new one. (so this can happen without more elaborate credential selection predicates)

@emlun
Copy link
Member

emlun commented Jun 15, 2021

Would it be reasonable if RPs could silently check for "does the user have some discoverable credential for this site"? So not allowing the RP to probe for any particular credential IDs (that would enable de-anonymization attacks), but just the presence of some credential they could use? Or would that be too invasive?

@eldanb
Copy link

eldanb commented Jun 20, 2021

That would definitely answer the RP's requirement described here; but I guess it does compromise privacy more than a "create or get" action.

@equalsJeffH
Copy link
Contributor

The RP techniques and webauthn API changes proposed in issue #1637 will (we hope) ameliorate the concerns expressed in this issue.

nsatragno added a commit that referenced this issue Jun 29, 2022
Add conditional UI flow

This PR enables a non-modal "conditionally mediated" UI feature for WebAuthn which RPs may utilize to provide a credential selection UI only if the user has a discoverable credential registered with the Relying Party on their authenticator (the latter being the "condition"). The credential is displayed alongside an autofilled username or password input field. This helps RPs solve the "bootstrapping problem" when migrating their user base from traditional username and password to WebAuthn: websites can fire a WebAuthn call while showing their typical username and/or password prompt without worrying about showing a modal dialog error if the device lacks appropriate credentials.

See also:
https://github.com/w3c/webauthn/wiki/Explainer:-WebAuthn-Conditional-UI
Fixes #1545

Overview "omnibus" issue: #1637
See also discussion in Issues #1356 #1533 #1568

Co-authored-by: Nina Satragno <nsatragno@gmail.com>
Co-authored-by: Jeff Hodges <nsatragno@gmail.com>
Co-authored-by: Emil Lundberg <emil@emlun.se>
Co-authored-by: Matthew Miller <mmiller@duosecurity.com>
@timcappalli timcappalli self-assigned this Sep 22, 2022
@kevvurs
Copy link

kevvurs commented Sep 22, 2022

This issue is essential for iOS 16 Passkeys to work with WebAuthN. Using the platform authenticator on iOS 16, I can setup a passkey on a website like https://webauthn.io for example, and then go to Settings app > Passwords and delete the passkey. Then if you try to login at the same site, it should follow WebAuthN spec for requesting the client to sign a challenge with the private-key. However, when the iOS passkey is no longer accessible, iOS will fall-back on the new "hybrid" flow, which is the QR code feature they recently debuted.

This is very bad because the RP has no way of knowing that the previously registered credential is inaccessible, and when asked for a credential that is not-present, Safari will now display cross-platform options, e.g. transports "usb" and "hybrid" authenticators. The user does not have a clear path to re-register their platform authenticator. Given a create-or-get spec, the RP can recover when a pre-existing credential, especially from the platform authenticator, is no longer available on an iOS client.

@timcappalli
Copy link
Member

timcappalli commented Sep 22, 2022

@kevvurs this sounds like an implementation discussion so I would discuss this issue on the FIDO-DEV list or in the WebAuthn Community Adoption Group. There are no current plans to add an additional method to WebAuthn but there may be other ways to address your concerns.

@mitar
Copy link

mitar commented Nov 24, 2023

I was also surprised that this does not already exist. When I heard about passkeys I really though that we finally got to the place where I can just show one "Sign in" button on the site and user can sign in. If user does not have an account, an account is created for them the first time. Similar to how social authentication works, only that the user keeps control through their device/platform or security keys. I also would find this further the privacy of the user: no usernames or even e-mails. Just opaque credential ID. They can provide e-mail maybe for account recovery, but it is not required. Also, browsers could then manage multiple accounts per site and sites would not even have to know about that (again a privacy win).

But currently it seems this is not possible. getOrCreate in my view (in that order) would achieve that for residental keys. I would ask if any key is registered for the site and if not, a new one would be created (of course with user giving consent to the browser to do so). In my view the response could really be PublicKeyCredential with AuthenticatorAttestationResponse or AuthenticatorAssertionResponse, depending if the key was created or just retrieved.

@mitar
Copy link

mitar commented Nov 25, 2023

I would also note this SO question which is asking for the same thing.

@sameadis
Copy link

sameadis commented Jan 17, 2024

Has this issue been resolved or at least has anyone come up with a work around? It's causing a terrible user experience and looks like we can't do anything about it.

@rlin1
Copy link
Contributor

rlin1 commented Feb 29, 2024

There are SPC use cases that will benefit from such an option as well.
Today it is an issue that it is not possible to determine whether a WebAuthn credential usable for SPC is available on a device as SPC will show an error message instead of the payment confirmation dialog.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@Risk Items that are at risk for L3 type:technical
Projects
None yet
Development

No branches or pull requests