Skip to content

Migrating passkeys to a new domain

Passkeys are resistant to phishing attacks because they’re bound to a specific domain (rpID). This does, however, raise some serious issues:

  1. Domain migration - at some point you may need to change your domain. If a passkey is registered to oldsite.com, how will your users sign in on newsite.com?

  2. Related domains - users may legitimately want to log in using a passkey from a different domain e.g. using an acme.com passkey on acme.co.uk.

Fortunately the specifications now support related origin requests, allowing you to accept passkeys registered to other domains.

For the examples we’ll use two domains: oldsite.com and newsite.com. Assume existing passkeys are registered to oldsite.com, but want to use newsite.com. You have a couple of options:

The simplest option is to continue using an rpID of oldsite.com on newsite.com.

Navigate to the passkey settings for your tenancy in the Passlock console.
Enter your old domain as the Relying Party ID.

Passlock tenancy settings for oldsite.com Passlock tenancy settings for oldsite.com

Continue to use an rpID of oldsite.com

Host a /.well-known/webauthn file at the root of oldsite.com (the rpID domain), whitelisting newsite.com:

https://oldsite.com/.well-known/webauthn
{
"origins": [
"https://oldsite.com",
"https://newsite.com"
]
}

This is the simplest approach, for both users and developers. There are some drawbacks:

  1. You need to host the webauthn file at oldsite.com indefinitely.

  2. Some browsers/devices ignore the Relying Party name and display the rpID to users, so they will see the message “do you want to sign in with your oldsite.com passkey?” or similar.

Alternatively, you can use newsite.com for new passkeys, whilst continuing to accept passkeys registered to oldsite.com.

Passlock tenancy settings for oldsite.com Passlock tenancy settings for oldsite.com

rpID is now newsite.com, with oldsite.com as a related origin

Host a /.well-known/webauthn file at the root of oldsite.com (the rpID domain), whitelisting newsite.com:

https://oldsite.com/.well-known/webauthn
{
"origins": [
"https://oldsite.com",
"https://newsite.com"
]
}

By default, the browser/device will present passkeys with an rpID of newsite.com.

If you need to authenticate oldsite.com passkeys after switching your tenancy rpID to newsite.com, override the rpID on that request:

import { authenticatePasskey } from "@passlock/browser"
const result = await authenticatePasskey({
rpId: "oldsite.com",
}, { tenancyId: "your-tenancy-id" })

This tells Passlock to fetch authentication options for oldsite.com, allowing the browser to present passkeys that were originally created for that rpID.

This approach allows you to support passkeys registered to an old domain, while also registering passkeys against the new domain.

After a user has authenticated with a “legacy” passkey, you can prompt them to register a new one, using the current domain/rpID. You can even delete the old passkey for them. The downsides are:

  1. You need to host the webauthn file at oldsite.com until all users have been migrated.

  2. You still need to decide whether to request a passkey for the old or new rpID. There is currently no single request that asks the browser for passkeys from both domains at once.