Skip to content

Preventing duplicate passkeys via excludeCredentials

Passkeys are typically synced across devices sharing the same cloud account ID e.g. a MacBook and iPhone signed into the same iCloud ID. You wouldn’t want a user to create one passkey on their iPhone and one on their MacBook, as they’d end up with two passkeys on both devices.

To prevent the user from creating multiple passkeys on a device, pass their known passkey IDs to the authorizePasskeyRegistration call.

backend/register.ts
const excludeCredentials = await lookupUserPasskeys(user.id);
const result = await passlock.authorizePasskeyRegistration({
excludeCredentials,
...
});

In your frontend be sure to check for the potential duplicate passkey error:

frontend/register.ts
import { Passlock, isDuplicatePasskeyError } from "@passlock/browser";
const result = await passlock.registerPasskey({ registrationToken });
if (result.failure) {
if (isDuplicatePasskeyError(result.error)) {
alert("You already have a suitable passkey on this device");
}
}

The same user may want to log into your system using multiple accounts e.g. personal and work. Make sure you only pass passkey IDs related to the current account. It’s quite legitimate for them to register multiple passkeys for different user accounts.

Whilst passkeys are synced across devices, this only applies across a platform/ecosystem e.g. Apple and to devices using a common cloud id.

If a user registers a passkey using their personal iPhone, it will be linked to their personal MacBook and iPad but not their work desktop or notebook.

They might want to use the roaming authenticator flow to sign in using their work device, then register a passkey on that device. In this case you would pass the existing passkey ID (linked to their personal iCloud account). Their work device will ignore it, and allow them to register a second passkey.

However if the user tries to register a passkey on one of their personal devices they would receive an error telling them that a passkey already exists.