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 discoverableCredential field in the API. #1565

Closed
lgarron opened this issue Feb 9, 2021 · 21 comments
Closed

Support discoverableCredential field in the API. #1565

lgarron opened this issue Feb 9, 2021 · 21 comments
Assignees

Comments

@lgarron
Copy link
Contributor

lgarron commented Feb 9, 2021

WebAuthn is rather difficult to learn, for a few reasons. Now that the spec has settled on "discoverable credentials", it's especially confusing that the actual browser API does not use that term at all, and uses a synonym ("resident key") that shares no words in common. I feel like this is "needless complexity" and does not match the "priority of constituencies". (It's also similar to a missing stair, although that term is usually used for more severe social concerns.)

I would love to see some investment in fixing this, for the benefit of those who learn to use the API in the future (or those of us who want to be able to understand their old code in the future 😛). For example:

  • Introduce discoverableCredential as a synonym for the residentKey auth selection field.
  • Specify that discoverableCredential overrides residentKey and residentKeyRequired*.

Since it looks like the spec will have at least 3 levels and level 2 is still being finalized, it is clear that browsers are still working on their WebAuthn implementations. I think it is still feasible to include a name change at this point and hope for it to land in browsers in a reasonable time frame — hopefully to the point that new folks never have to learn the phrase "resident key".

* If it seems valuable for the caller to know which field took precedence, the existing credProps extension could be modified to accommodate that.

@lgarron lgarron changed the title Support discoverableCredential fields in the API. Support discoverableCredential field in the API. Feb 9, 2021
@akshayku
Copy link
Contributor

akshayku commented Feb 9, 2021

Level 2 is done. In Level 3 we can clarify more if people are still confused but would prefer no more variables.

@lgarron
Copy link
Contributor Author

lgarron commented Feb 10, 2021

In Level 3 we can clarify more if people are still confused but would prefer no more variables.

I don't think it's so much a problem of clarification. If you dig, the spec unambiguously states that they mean the same thing (which is quite helpful!). But as it stands, there is no way to infer this if someone doesn't tell it to you: every person learning learning the spec has to learn this inconsistency, and has to document/explain it to every colleague who interacts with their WebAuthn implementation.

I'm advocating that the cost of introducing a synonym is worth the ability for future web developers to use a single consistent term (thus prioritizing authors over implementers and spec authors).

@selfissued
Copy link
Contributor

It's my sense that adding this would make things more - not less - complicated. We should close this on that basis.

@lgarron
Copy link
Contributor Author

lgarron commented Feb 10, 2021

It's my sense that adding this would make things more - not less - complicated. We should close this on that basis.

Could you explain this perspective?

From my perspective:

  • Fairly few sites have deployed anything with discoverable credentials.
  • Browsers are working from the living spec (i.e. it doesn't seem that the finalization of level 3 needs to be a barrier to browser implementation).

If all browsers support this by the time that more sites start working with discoverable credentials in earnest (which probably won't be until Android Chrome ships it, at least), tutorials and libraries can refer exclusively to discoverable credentials in prose and in code. "Resident key" would be a footnote that most site authors wouldn't have to worry about.

To me, that sounds a lot simpler for most of the ecosystem than permanently leaving a level of indirection between the same thing in prose and code. And if I understand the priority of constituencies correctly, this is preferable to keeping implementations/spec as they are. (I know the priority of constituencies not an absolute thing, but in this case I'm advocating that the increased implementation complexity is fairly moderate and warranted.)

@bathos
Copy link

bathos commented Jul 1, 2021

It's my sense that adding this would make things more - not less - complicated. We should close this on that basis.

I had to learn this and have repeatedly found myself double checking my understanding of these options. It’s already hard to feel confident about much here as a learner, so issues like this really keep you at sea. I had to leave multiple comments explaining naming quirks (this isn’t the only one, e.g. "name" and "displayName" are both display strings) to give other folks reading the code I just wrote a fighting chance at understanding it. I don’t understand this conclusion.

@arshadnoor
Copy link

I have gone on public record, that FIDO was invented because PKI-based TLS ClientAuth - the original passwordless authentication protocol - was too complex for application developers to understand/use within web and rich-client applications. I didn't think a day would come where, despite being in the FIDO Alliance for nearly 7 years, I would shake my head at the complexity of what FIDO/WebAuthn has become.

Looking at the Level-2 spec, here is what I see - including the 3 marketing related names (in bold italics), there are at least 20 different names to define FIDO/WebAuthn "stuff" in the specification (I'm not sure whether I've missed others):

  1. Client-side discoverable Credential
  2. Client-side discoverable Public Key Credential Source
  3. Discoverable Credential
  4. First-factor Roaming Authenticator
  5. Non-discoverable Credential
  6. Non-Resident Credential
  7. Passkey
  8. Platform Authenticator
  9. Platform Credential
  10. Resident Credential
  11. Resident Key
  12. Roaming Authenticator
  13. Second-factor Platform Authenticator
  14. Second-factor Roaming Authenticator
  15. security key
  16. Security Key
  17. Server-side Credential
  18. Server-side Public Key Credential Source
  19. User-verifying Platform Authenticator
  20. Windows Hello

AFAICT, from a technical pov, there are only 3 basic "objects" that people need to keep track of in their heads when reading about FIDO/WebAuthn: Authenticator, Credential and Key. Everything else merely describes these objects or the context in which they are used.

Is it possible to simplify the naming to use just the 3 objects and embellish them with decorative symbols to describe them or represent the context in which they are used? For example, when a number is raised to the power of 2 or 3, we don't say "squared number" or "cubed number" in the text - we denote them as N^2 or N^3. Could the specification do something similar with the 3 objects and simplify the spec?

And, the API to references these names, can the desired properties not just be passed as attributes of first-class Authenticator, Credential or Key objects?

I'll leave it to more creative minds to come up with the symbols that can denote context better than I can: color-coded, graphical symbols... anything that can help reduce the complexity of reading this specification.

P.S. I really, really wish the companies behind the marketing names for FIDO had not added to the confusion. I'm a strong believer that an informed consumer is the best defense the internet can have - but the more we obscure FIDO, the easier it will likely become to manipulate ill-informed users in time.

@cyberphone
Copy link

cyberphone commented Jul 7, 2021

Hi @arshadnoor As a FIDO "newbie" I also find the docs and specs overwhelming. However, it's getting worse since Google supported by the FIDO Alliance, EMVCo, and the W3C intends to ship a payment-authorization-standards-to-be in Chrome later this year, which (as far as I can tell), follows the upper diagram of the following picture although considerably simpler (as well as more powerful) solutions have been suggested like the FIDO Web Pay scheme outlined in the bottom diagram:
Untitled

@emlun
Copy link
Member

emlun commented Jul 13, 2021

@arshadnoor Thanks for pointing this out, I'm not sure how much we can feasibly do but I agree there seem to be some simplifications we can make. I've listed some in #1648.

I think a new symbolic language seems more likely to increase cognitive load than reduce it, though, and would probably harm accessibility (and color coding even more so). So I don't think it seems useful to depart from the general "<adjective> Authenticator/Credential/Key" pattern that most of these definitions currently use.

@arshadnoor
Copy link

You're welcome, Emil (@emlun). I concur that it may be too late to "close this barn door" now; but, whatever can be done to simplify descriptions, would be welcome.

IMHO, FIDO is at a pivotal point currently. Perhaps it might be prudent to focus on simplifying the adoption of Resident Credentials first (given recent announcements by 2 major consumer OS suppliers) so barriers to consumer adoption are eliminated. Unless consumers adopt it rapidly in the next 12 months (which depends on major web-sites/apps implementing the capability and promoting FIDO aggressively on their sites), I fear it might sputter.

P.S. What I think would really help is for manufacturers of hardware devices (PCs, tablets, mobile) to bundle a Security Key with each device - much as they bundle a power cord - so OS manufacturers would educate consumers from the moment their new devices are setup, and Account Recovery is also addressed with the bundled Security Key. While this does add a small cost to consumers, I think data breaches related to passwords over the last 15+ years have cost consumers far more than that already.

@equalsJeffH
Copy link
Contributor

WRT to efforts to ease adoption, please see issue #1637 where we are proposing an overall approach we feel will do so. We do not feel that discrete security keys will have meaningful uptake in the broad consumer space regardless of how available and low cost they are. User verifying platform authenticators are emerging and the RP best practices and webauthn API changes outlined in issue #1637 will, we think/hope, ease adoption and migration of users from username+password to WebAuthn/FIDO.

wrt terminology and nuances thereof, please see #1648 (comment) and follow-on comments.
BTW, "resident credentials" is a clearly deprecated term and I've been pleased of late that many/most folks are using "discoverable credentials" instead. If not for API backwards compatibility issues (sigh), we would have eradicated the former term from the spec.

@arshadnoor
Copy link

I don't deny that User Verifying Platform Authenticators (UVPA) are likely to be the most effective way to get the vast majority of consumers to adopt FIDO. However, I also believe that the use of an external Security Key simplifies FIDO key lifecycle management for consumers better than any other alternative.

While I recognize what Apple has done with Passkey simplifies that lifecycle management for their consumers, Apple can do what they want in their "walled garden" and get away with it - they own all the pieces to implement what they want with Passkey. The rest of us have to live with multiple, dissimilar devices with different operating systems, different browsers, different transport protocols, different levels of consumer knowledge/capability, etc. Trying to synchronize FIDO key-pairs across that smorgasbord of technology, vendor implementations and terminology will make this protocol/specification a nightmare. We will end up with partially implemented specifications from multiple vendors that will make interoperability a pipe-dream.

IMO, Security Keys work well currently. If hardware vendors bundled one with new devices, it will simplify Account Recovery, make registering with multiple UVPA as easy as pie, and save the FIDO ecosystem an enormous amount of time/money keeping things simple for everyone! It is complex enough as it is right now.

Just a word of caution: PKI did not become the hairball it is, overnight. It was beaten into submission by all the use-cases dozens/hundreds of RPs wanted to see in a digital certificate, when in reality, if they kept X509 focused on just authentication, and relegated the use-cases to applications, we might have been using strong authentication for a couple of decades now. Instead, we were forced to invent FIDO to reinvent PKI - but are traveling down the PKI road again!

(I think there's a thread somewhere in this forum - or a FIDO forum - that sounded a similar alarm about including extensions in the FIDO registration/authentication protocol 4-5 years ago).

@lgarron
Copy link
Contributor Author

lgarron commented Mar 23, 2022

I'd like to reiterate that after years of working with WebAuthn, I still believe this is the #1 low hanging fruit for avoidable confusion. As platforms work on passkey implementations, this auth selection field will become more and more relevant.

Would it be possible to get a signal from spec authors about the feasibility of a discoverableCredential field as described in the first post? Would you be interested in a PR that updates the spec to accommodate this, or would there be larger concerns before that is appropriate?

@Firstyear
Copy link
Contributor

@lgarron you can't mix discoverable and non discoverable credentials in most work flows. Additionally, most credentials have no way to inspect what discoverable (resident keys) exist and have no method to manage them. For example, I have a yubikey, and there is no tool to list what rk's exist on it, nor any docs that I can find about what happens if I fill that storage.

Similar apple will silently replace your discoverable keys in the background if you re-register them on the same domain (even with a different username), meaning you can only have one key per site (so you can't multi-account from a single device).

Generally, discoverable keys have so many sharp edges that for users it will likely present a confusing and risky workflow. IMO discoverable keys are there so that certain large mega corps with strictly controlled devices, who have this tooling and such, can do their own thing, but there is a definite lack of attention to rk's for consumers.

@MasterKale
Copy link
Contributor

@lgarron It was a little ambiguous to me in the OP, to clarify your ask: you're simply proposing adding a new property discoverableCredential to AuthenticatorSelectionCriteria that is a alias of the existing residentKey? And parsing logic related to residentKey would then become "if residentKey or discoverableCredential are "required" then..."?

If that's so that seems pretty reasonable to me. Assuming such a thing would make it into L3 then maybe in L4 we could deprecate the residentKey argument completely 🤔

@Firstyear
Copy link
Contributor

@lgarron It was a little ambiguous to me in the OP, to clarify your ask: you're simply proposing adding a new property discoverableCredential to AuthenticatorSelectionCriteria that is a alias of the existing residentKey? And parsing logic related to residentKey would then become "if residentKey or discoverableCredential are "required" then..."?

If that's so that seems pretty reasonable to me. Assuming such a thing would make it into L3 then maybe in L4 we could deprecate the residentKey argument completely 🤔

I have previously asked about a way to specify per-credential selection criteria which was denied by this WG, because an authentication challenge is considered to be targetting a single credential with a narrow credential class, rather than about selecting between criteria for a diverse range of possible authenticators.

As a result it's up to the RP to pre-select in a work flow for the user what credential they want to potentially use, including the distinction between rk and not.

@lgarron
Copy link
Contributor Author

lgarron commented Mar 23, 2022

Similar apple will silently replace your discoverable keys in the background if you re-register them on the same domain (even with a different username), meaning you can only have one key per site (so you can't multi-account from a single device).

Whether a site wants to work with discoverable credentials or not, the first half of this (silent overwriting) is already a fact of life with two platform authenticators (Windows Hello and Safari), regardless of whether the site intends to use server-side credentials only. 😔
I don't follow the second half, though, since I'm able to create multiple discoverable credentials in Safari if they're for different accounts. (In any case, that's not really relevant to this issue, which is about API ergononics.)

@lgarron It was a little ambiguous to me in the OP, to clarify your ask: you're simply proposing adding a new property discoverableCredential to AuthenticatorSelectionCriteria that is a alias of the existing residentKey? And parsing logic related to residentKey would then become "if residentKey or discoverableCredential are "required" then..."?

Yeah, although ideally the other way around (i.e. rename discoverableCredential to residentKey, and make residentKey as a legacy alias for discoverableCredential).

I suggested in the original post that discoverableCredential would completely overwrite residentKey, but it doesn't matter exactly — since the goal here is to make the use of residentKey a legacy edge case.

If that's so that seems pretty reasonable to me. Assuming such a thing would make it into L3 then maybe in L4 we could deprecate the residentKey argument completely 🤔

I would love to have a chance of dropping residentKey to avoid any potential confusion. 😃
But for now, being able to prioritize discoverableCredential in all code (most importantly, all public code snippets) would be a significant step to reducing potential confusion for new RP devs.

What would be a good next step forward?

@bathos
Copy link

bathos commented Mar 24, 2022

Generally, discoverable keys have so many sharp edges that for users it will likely present a confusing and risky workflow. IMO discoverable keys are there so that certain large mega corps with strictly controlled devices, who have this tooling and such, can do their own thing, but there is a definite lack of attention to rk's for consumers.

Funny enough I always figured the only reason non-discoverable/non-resident keys were in the picture was to account for “certain large mega corps” and maybe a handful of tech utopians, so this statement seems pretty surprising! I work on a (decidedly) non-megacorp app with a userbase where few if any people have heard of yubikeys. If the browser pops an “insert your space dongle” modal they get worried they have a virus. It’s difficult enough to provide a solid user experience with webauthn without this in the mix and an inscrutable roadblock being placed in front of our real users for the sake of a hypothetical user who’s not there is a non-starter. This is not a judgment about yubikey and co, it’s just our reality.

I don’t claim to understand the whole picture here or even a sizable fraction of it, but hope sharing this POV could help the API designers understand why webauthn has become a discoverable-platform-credentials-or-nothing thing for developers who need to serve demographics that aren’t inside the tech bubble.

@serianox
Copy link

I have previously asked about a way to specify per-credential selection criteria which was denied by this WG, because an authentication challenge is considered to be targetting a single credential with a narrow credential class, rather than about selecting between criteria for a diverse range of possible authenticators.

As a result it's up to the RP to pre-select in a work flow for the user what credential they want to potentially use, including the distinction between rk and not.

This has to do with the capabilities to step-up from credentials to discoverable credentials in the registration/login flow

  • authenticators may return a discoverable credential even if not requested by the RP
  • RP can use a discoverable credential in the default authentication scheme, i.e. passing the discoverable credential ID in the allow list to explicitly select it

It's not non-discoverable vs. discoverable, it's discoverable being an additional property of a credential.

A RP can provide a registration flow with options.authenticatorSelection.residentKey = "preferred", and then provide an authentication flow with 2FA/passwordless passing all the registered credentials including the discoverable ones, or usernameless waiting for a discoverable credential to be used.

@emlun
Copy link
Member

emlun commented Mar 24, 2022

@bathos: If the browser pops an “insert your space dongle” modal they get worried they have a virus. It’s difficult enough to provide a solid user experience with webauthn without this in the mix and an inscrutable roadblock being placed in front of our real users for the sake of a hypothetical user who’s not there is a non-starter.

This seems like the kind of problem allowCredentials.transports is meant to solve, have you tried that? If you know that all your users only use platform (built-in) authenticators, you can set that to ["internal"] for all credentials, which should ideally suppress the prompt to connect an external device. The intended use is that you store the AuthenticatorAttestationResponse.getTransports() result for each credential and echo that value back in allowCredentials.transports. Unfortunately this won't work for "username-less" authentication (empty allowCredentials) though.

@Firstyear: I have previously asked about a way to specify per-credential selection criteria

I don't think "per-credential" applies here, since this is about credential creation, not authentication. Pardon me if I misunderstand.

@lgarron I would like to see this change and deprecate the old fields, but I worry that backwards compatibility concerns could make it more confusing and complex rather than less. At least for a transitional period, RPs would need to specify both discoverableCredential and residentKey (and maybe even requireResidentKey) in case the user's browser is not yet updated to recognize the new name. This was the concern in the meeting minutes as well. We can bring it up again in the next meeting.

@bathos
Copy link

bathos commented Mar 24, 2022

Unfortunately this won't work for "username-less" authentication (empty allowCredentials) though.

This is why we don’t use it, yeah.

Or nearly don’t. We do potentially use it in a single pretty specific authentication flow:

  • The client has authenticated and believes this authenticated session is still active
  • The session gets terminated from the server’s POV by means not initiated through the client (so it’s still “logged in” but isn’t).
  • The user takes an action that hits our API. this fails but the client now knows there’s no authenticated session.
  • However we’re here because the user actually tried to do something just now, so...
  • If the client’s defunct session was one authenticated with a public key, this is where we would use allowCredentials + transports. Here we have knowledge of a specific id (which would never otherwise be true) and here we want to constrain the lookup/request to one specific user account or fail (which would never otherwise be true).
  • If this (or a distinct path for PasswordCredential) succeeds and gets the same user back, the originally rejected request has become safe to repeat. We do and from there everything just continues exactly as it would have had they really been authenticated to begin with.

This isn’t a common thing to hit at all as our sessions are long lived and refresh with activity by default (and multiple tabs share pertinent session change events with each other for logout, etc). It could happen anyway for a few reasons, but the primary motivation was a single user. This user believes that it’s important to clear cookies and other browser data multiple times throughout their day to increase “security” (it’s like “drink seven glasses of water” or something). I lightly suggested this may not always be necessary but it was the kinda thing where you could tell he might feel proud of his savviness and I didn’t wanna mess with anybody’s self image like that, he is a sweet guy and it’s harmless anyway. Go ahead and delete em! Have fun! Still, we’d see unique new errors coming through due to this a few times a day since he would attempt to use the app when it was in this pseudo-logged-in state right after resecuritying his computer. The diagnostic noise wasn’t great and it just kinda felt bad knowing this was part of his experience of the app — i knew that at least sometimes it would have to mean he lost some data he’d just entered.

So although he doesn’t know it, I built this flow for him. And it was like allowCredentials & transports were tailor made for it. Worked great. No matter how hard he securitied he was no longer losing the subsequent auth-requiring-action and the UX was super smooth.

And later we got a second habitual session-deleter! (If you build it ...) I didn't understand the point of allowCredentials originally, but here’s a user story that couldn’t have been addressed without it.

@timcappalli timcappalli assigned timcappalli and unassigned akshayku Sep 19, 2023
@timcappalli
Copy link
Member

We have discussed this on many WG calls over the past 2+ years. As mentioned in many of the comments, a change like this would cause challenges for backwards compatibility, and this could further complicate the developer experience in the mid term (having to specify potentially 3 options).

Improving developer guidance (e.g. via passkeys.dev) is likely to have a higher impact.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests