webauthn icon indicating copy to clipboard operation
webauthn copied to clipboard

Consider RP ID migration use cases

Open MasterKale opened this issue 2 months ago • 12 comments

Description

We're seeing some websites facilitate the migration of current passkey users to passkeys bound to a new RP ID. For example, https://x.com is communicating their upcoming migration of users away from twitter.com-scoped passkeys to new passkeys scoped to x.com. Without diving too deep into their migration UX, it seems X/Twitter is requiring users to go through a typical modal registration flow.

Over time it's inevitable we'll see some other sites want to facilitate a similar migration. Some discussions around this explored a couple of possible ways the spec might be expanded to make it easier for an RP to more seamlessly migrate their users to passkeys at a new RP ID. I'm capturing some of them here to kick off discussions around how, if at all, we might add or refine functionality in L4 to make RPs' lives easier:

  1. Open up conditional create to not require an auth to have just occurred. This could benefit sites that use long-lived sessions and thus users are not often asked to re-auth
  2. Add a new signal of some sort to allow an RP to trigger the rebinding of an existing passkey to a new RP ID
  3. Do nothing and expect RPs to use the typical modal WebAuthn registration flow

This list of options shouldn't be considered exhaustive. We should talk about the RP ID migration use case specifically and see what ideas might come out of such discussions.

Related Links

N/A

MasterKale avatar Oct 27 '25 01:10 MasterKale

IMO, this is already possible today, and just needs some developer guidance on passkeys.dev:

  • Related Origin Requests gives you access to the "old" passkey on the new origin.
  • Conditional Create allows you to automatically create a "new" one after a sign in with the "old" one
  • Signal API allows you to clean up the old passkey, via an iframe (although we could probably enhance this to use the ROR origin list to allow cross-origin cleanup without the iframe)

What's missing from this combo?

timcappalli avatar Oct 27 '25 02:10 timcappalli

ROR definitely feels like a piece of the puzzle, especially for its unlocking cross-origin registration 🤔

Conditional Create allows you to automatically create a "new" one after a sign in with the "old" one

A potential issue with this is, if a site uses long-lived sessions, when would the RP be able to trigger this for already-logged-in users? I'm not saying our position couldn't eventually be "use everything as-is" but we should at least talk about it as a group.

MasterKale avatar Oct 27 '25 02:10 MasterKale

Why do you need to trigger it for logged in users? Why is this different than any other flow where CC is used? IMO, that's an over optimization for a fairly limited use case.

timcappalli avatar Oct 27 '25 03:10 timcappalli

I think we have most of what we need for this, but it's not quite practical to do yet:

  • Even if you use related origins, you still can pass a single relying party identifier. It's tough to support usernameless flows when you can't tell which RP ID your user is under.
  • The user may have multiple passkeys. Which one is your conditional create call replacing? Even if you only call conditional create after a sign in with a passkey (to give you some confidence that specific passkey will be replaced), it could be that a different one gets replaced! Ignoring this fact and calling the signal API after could result in the user losing their valid passkeys.

There's also the fact that conditional create doesn't quite work for other forms of auth other than password yet, although I don't think that's necessarily a WebAuthn spec issue.

Here's an exciting proposal: what if we have user agents and authenticators show the origin of the request instead of the relying party identifier? This doesn't solve everything: if a company e.g. sells their old domain, they lose access to the passkeys. But it at least solves the branding issue.

nsatragno avatar Oct 27 '25 18:10 nsatragno

  • The user may have multiple passkeys. Which one is your conditional create call replacing? Even if you only call conditional create after a sign in with a passkey (to give you some confidence that specific passkey will be replaced), it could be that a different one gets replaced! Ignoring this fact and calling the signal API after could result in the user losing their valid passkeys.

Would conditional create really replace any passkey under the old RP ID though? I'd imagine the client allowing the request if the user has another passkey with matching username under a related linked RP ID, but it wouldn't replace that passkey. (Just conditional create requests don't replace passwords either.) If the RP wants to clean up the existing passkey under the old RP ID, they can do so via the Signal API, right?

(But, as you point out, passkey assertions being limited to a single RP ID are really the limiting factor here.)

kreichgauer avatar Oct 27 '25 18:10 kreichgauer

I'd imagine the client allowing the request if the user has another passkey with matching username under a related linked RP ID

The client may have two authenticators attached with a passkey for that { RP ID, user handle }, but conditional create returns a single passkey back. You could try to be smart and e.g. look at the aaguid, but that's not guaranteed to be unique either.

nsatragno avatar Oct 27 '25 19:10 nsatragno

I wonder if this would be vulnerable to a denial of service? Say that I have a site https //naughty.server.com and then I do a related origin request/condition create or whatever combo we are talking about here, then I could potentially replace the users passkeys.

I think consideration of malicious actors is needed here.

There needs to be some kind of verifiable linkage between the old origin and the new origin you plan to recreate under.

Firstyear avatar Oct 27 '25 23:10 Firstyear

Would conditional create really replace any passkey under the old RP ID though?

fwiw I wouldn't ever propose we enable replacing or reusing passkeys as part of a migration strategy. Rather, I'd approach this from the angle of "how can we make it easier to conditionally register a passkey" and encourage a new passkey to be created for a valid RP ID for the current origin, regardless of the auth method used to log in (password, another site's passkey via Related Origins, etc...)

MasterKale avatar Oct 27 '25 23:10 MasterKale

Ahh I guess you could use conditional create to create new passkeys and leave the old ones around until you're reasonably sure the migration has happened. In that case the fundamental piece we're missing is the ability to ask for multiple RP IDs on assert.

nsatragno avatar Oct 29 '25 19:10 nsatragno

In that case the fundamental piece we're missing is the ability to ask for multiple RP IDs on assert.

Would even this be necessary? In identifier-first auth flows the RP should have enough insights about a user's passkeys to know which one RP ID to request use of 🤔

MasterKale avatar Oct 29 '25 19:10 MasterKale

Might be good to write out some developer guidance on how to address this right now, and then evaluate what is missing, before getting into too much solutioning.

https://github.com/passkeydeveloper/passkeys.dev/issues/452

timcappalli avatar Oct 29 '25 19:10 timcappalli

Even for identifier first flows there's value: say the user has two passkeys, one for each ecosystem of devices. One of the passkeys was migrated to the new RP ID, the other has not. The RP can only get an assertion for one of those at a time.

nsatragno avatar Oct 29 '25 19:10 nsatragno