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
[Superset] Updating credential metadata and requesting deletion of stale credentials #1967
Comments
Yes please. The first one especially is highly desirable because passkey self-service must happen in two places, once on the RP's side and then a follow-up action within the provider's interface, and it's very easy for the two to fall out of sync. And I see adding the ability to update a credential's username and display name as highly desirable because it makes WebAuthn adaptable to real people problems. People change their legal names, online handles, email addresses, and other things that get used as usernames for a multitude of reasons, and right now the story for getting passkeys to respect this is limited to, "have the RP make a There's too much ambiguity in this current process that users can end up with two credentials, one with their old handle and a second one with their updated handle, thus exacerbating the RP's problems. I'd love for us to spend some more time on this in upcoming meetings to try and discover a better solution. |
In the interest of having something concrete to discuss, here's another attempt (somewhat inspired by my previous one, but rather different). How about a new extensions: {
updateCredentials: {
user: {
id: new Uint8Array([1, 2, 3, 4]), // User handle of the user account whose credentials to update/garbage-collect
name: "example", // New value for user.name
displayName: "Example User", // New value for user.displayName
},
validCredentials: [
// List of all of credentials valid for this account
// Credentials with these IDs have their user.name and user.displayName updated
// Credentials with above user handle and none of these IDs are deleted
{ type: "public-key", id: new Uint8Array([96, 231, 209, 27, /* ... */ ])},
{ type: "public-key", id: new Uint8Array([165, 225, 44, 123, /* ... */ ])},
{ type: "public-key", id: new Uint8Array([112, 235, 14, 6, /* ... */ ])},
/* ... */
],
},
}, As noted in the inline comments, the idea is:
The main idea is that this way the RP doesn't need to track state changes over time, rather it only needs to report the current state. Thoughts? |
I'll start: You probably don't want to expose all this information before the user is authenticated. This also doesn't work at all when the user isn't yet identified (empty So it needs to be something you can call after successful authentication. Maybe a static function on Or maybe the extension outputs a callback that the RP can invoke after retrieving the right state for the user? const credential = await navigator.credentials.get({
publicKey: {
// ...
extensions: {
updateCredentials: true, // Request that extension outputs include the callback
},
},
});
// Finish authentication on backend
const userSession = await finishAuthentication(credential);
credential.getClientExtensionResults().updateCredentials(userSession.updateCredentials); |
I don't think we want to tie the update to an assertion, whether through an extension or a method on the returned I prefer the static function approach. Especially if we can update other credential types on the same call. A possible API could be, navigator.credentials.update([
{ type: "public-key", id: ..., displayName: ..., etc ])} // missing attributes are ignored
]);
navigator.credentials.delete([
{ type: "public-key", id: ...])}
]); These would not be guaranteed to do anything. The browser would execute these actions opportunistically. For example, if a user just used a security key to sign in and the RP calls In my mind, an RP would call the same
-- There are pros and cons to making this an action users have to consent to (and therefore, that we can inform the website that an update took place) vs a silent update. I think I prefer making these updates silently, so that RPs can build whatever experience they want around it, and we don't need to bother users twice. Showing UI for an update would also not be that dissimilar to calling |
I think I think Where We're already seeing a ton of issues in adoption of passkeys in general with confusion about how to enable them, how they work, and the ui/ux to even use them to do a login. I think throwing in more elements here could just further damage the situation. So from the view of an RP and an RP library, my overall assessment is that while these functions have interesting properties, I likely would not implement them or use them because they risk confusing users. This is similar to my assessment of functions like isUVPAA and isPasskeyAvailable, where these functions only add extra complexity to interactions and workflows, leading to user confusion and rejection of webauth. As a more general meta commentary, there are two aspects to standards - the standard as written and envisaged by it's authors, and the standard as actually used. I think that webauthn has a huge surface area in the standard, and really most RP's will only use a fraction of that. So far that surface area at a high level is:
Outside of those use cases, we have a lot of "fluff" in the spec that the majority of RP's won't ever deploy or use. And the small percentage that do deploy and rely on those fluffy components will run into issues. So we need to ask ourselves is |
The credentials should always be deleted (or rendered inoperable) on the server side. The way I envision it, deleting the credential on the authenticator is a nice-to-have. If the user tries to use that credential to sign in later, the RP can then and there attempt deleting it again, where the deletion is a lot more likely to succeed. |
This is why I proposed a state transfer approach instead of an action-oriented approach - the former eliminates the problem by letting the authenticator(s), instead of the RP, figure out what needs to change to reflect the most recent state. If the user unplugs their USB security key before clicking "delete" in the RP UI, that doesn't matter because the RP can just send the current state at the next opportunity (be it login, a credential management operation or whatever). |
I think you both have missed my point - the UI/UX around trying to coordinate a delete function as an RP will be extremely tricky to communicate to a user, and tough for an RP to coordinate and drive. Regardless of any technical ideas, I think this risks being added to the spec and not used by RP's. |
(with @nsatragno) We've had multiple requests for this from RPs, and some consider it blocking to implement discoverable flows as they correctly point out that account selectors will forever have stale info in them for many users. So I think this is a real issue and a solution here would be useful. (we can ask some of the RPs to chime in here if needed) We think the state transfer approach is better for the general update - as that can be made repeatedly for cheap and thus help propagate updates to authenticators/providers that aren't always available, depending on what client the user is on. However, that only works if the user is authenticated already, so an action-type report for when a credential is rejected and no user is signed in seems useful as well. We also agree trying to make WebAuthn a full CRUD-like API is not workable, nor desired. Rather, an opportunistic API for RPs to convey information back to authenticators and credential providers on a best-effort basis seems both useful and doable. For the lack of a better word we've been thinking about as reports RPs make to the client, knowing that sometimes they may go nowhere. As a concrete proposal, we posted this explainer: https://github.com/w3c/webauthn/wiki/Explainer:-WebAuthn-Report-API-explainer |
Maybe a crazy take on the other direction, but I think would make things simpler: if passkeys are designed to identify a single person (maybe using multiple devices in sync), why not just remove the If they wish a label, users can still label a passkey directly on their client, but not necessarily with a name coming from the RP, the same way right now it's possible to change it in some client implementations. For example, if someone shared a passkey with me, my client could automatically label the passkey as "Alice's passkey"; or I could create a second passkey for an RP and my client would ask me how I want to name it so I can distinguish them; but by default they would have no label. RPs can still allow a single passkey with multiple accounts by presenting an account selector after login. This does not address the point of credential deletion, but I think that's quite a differentiated need. Maybe this doesn't need to be provided, either. After all, if I change the lock on my apartment, there's no more lock; I am responsible for disposing of the key. I can see many ways this could go wrong: RPs that disappear without wiping their user's passkeys (for example, the company goes bankrupt or the domain name is changed) or an RP accidentally removing their user's passkeys and locking them out. |
Then just don't use residentKeys/discoverableCredentials. This whole issue is avoided if you do that. |
Not really, they're still useful to present credentials for a given RP. In 99% of cases you will have 1 credential, in the other cases a label can come in handy. |
As some pointed out, it is impossible nor desirable for a RP to delete remotely stale credentials:
I think the only way to delete stale credentials is a user side garbage collection - the client could list all the credentials/RP and use a well-known endpoint to check if the credential still exists or can be deleted. |
A |
There's no reason why we couldn't have a nice autofill UI even if the RP provides an Having |
OT, but if you want to build a username first into password + autofill UI flow today you can do it. See |
The RP cannot populate the allow list unless it knows who the user is, so they'd always have to ask for a username. Granted that could be autofilled, but it'd always be two confirmations for the user, as we could not automatically submit usernames to websites wihtout user approval. We are definitely finding that improved convenience is a much more appealing reason to use passkeys, for both RPs and users. The conclusion of that is that we really want to support a single-confirmation "type nothing" flow (aka usernameless). Our goal is improved security, but convenience is the carrot.
It's not the greatest reason, but there are established use cases for FIDO/WebAuthn in reauth, where an RP explicitly does not want an account selector - only a UV step. That simplicity allows broader deployment of reauth, which is impactful for both friendly fraud and cookie theft. The fact that a populated allowList is the only way for an RP to signal this is maybe subpar, but we can consider that legacy at this point I think.
I think at least I believe this is more complex in the end. Besides defining a protocol between authnrs/providers and RPs (which is doable), there are non-trivial privacy and transparency implications of how providers should use this when the user is not involved. There are certainly privacy and DOS concerns with the report API, but here the user agent has full power to mitigate those.
That is a fairly deep change to ask of RPs, as it can go as deep as modifying their data model for accounts. I also don't think the goal is to make passkeys represent a person, as that brings a whole host of complex and non-technical issues over treating passkeys as account credentials only. |
Some thoughts from our perspective as a bigger-sized RP: the proposal by @nsatragno + @arnar addresses real concerns we have in planning passkeys rollout with existing users (and we also consider it blocking).
We thought we would "chime in" as an RP. We know our focus here is on consumer-heavy situations, primarily focusing on passkeys/discoverable credentials. This is not to say all other perspectives are not important; it's just our perspective. |
This seems badly implemented across browsers. E.g. Safari doesn't seem to support this. It seems to work on Chrome though. |
These scenarios are planned to be addressed by: https://github.com/w3c/webauthn/wiki/Explainer:-WebAuthn-Report-API-explainer |
This issue is to consolidate a bunch of issues from over the years around deletion of stale credentials, updating properties of existing credentials, etc and provide a single issue to continue discussion. There was general consensus at TPAC 2023 that something like this is needed.
Existing Issues
All of these issues have now been closed. Please continue discussion here.
#1456: Personal information updates & webauthn
Ability to update things like
name
anddisplayName
without creating a new credential.#1779: Facility for an RP to indicate a change of displayName to a discoverable credential
Similar to 1456, but specific to displayName
#1560: Cleanup when creating discoverable credentials with attestations
Essentially allow for clean up of stale credentials. For example, a credential that was deleted RP-side, or a credential that doesn't meet RP requirements.
#1696: FIDO credential decommissioning
High Level Requirements
Trends observed in these issues:
name
and/ordisplayName
has changedThe text was updated successfully, but these errors were encountered: