Published: November 12, 2024, Last updated: November 29, 2024
The WebAuthn Signal API lets relying parties signal existing credentials to connected passkey providers. This lets a supporting passkey provider update or remove incorrect or revoked passkeys from its storage so users are no longer offered them.
Compatibility
Chrome supports Signal API on all desktop platforms and Android.
Safari is supportive but not yet implemented. Firefox hasn't yet shared its opinion.
Google Password Manager can update passkeys to reflect the signal. Chrome extension-based passkey providers on desktop decide whether to reflect the signal.
Background
When a passkey (a discoverable credential) is created, metadata such as a username and a display name are saved to the passkey provider (such as a password manager) along with the private key, while the public key credential is saved to the relying party's (RP's) server. Saving the username and display name helps users identify which offered passkeys to use for sign-in when prompted. This is especially useful when users have more than two passkeys from different passkey providers.
However, there are a few cases where inconsistencies between the passkey provider's passkey list and the server's credentials list can cause confusion.
The first case is when a user deletes a credential on the server. This leaves the passkey in the passkey provider untouched. The next time the user tries to sign in with a passkey, the passkey provider still presents that passkey to the user. However, the attempt to sign in will fail because the server cannot verify the public key that was deleted.
The second case is when a user updates their username or display name on the server. The next time the user tries to sign in, the passkey in the passkey provider continues to display the old username and display name even though it's updated on the server. Ideally, these are synchronized.
Signal API
The Signal API is a WebAuthn API that resolves these inconsistencies by letting RPs signal changes to the passkey provider. There are three methods:
PublicKeyCredential.signalUnknownCredential: Signal that a credential does not existPublicKeyCredential.signalAllAcceptedCredentials: Signal a list of saved credentialsPublicKeyCredential.signalCurrentUserDetails: Signal updated username and display name
Signal that a credential does not exist
const credential = await navigator.credentials.get({ ... });
const payload = credential.toJSON();
const result = await fetch('/login', { ... });
// Detect authentication failure due to lack of the credential
if (result.status === 404) {
// Feature detection
if (PublicKeyCredential.signalUnknownCredential) {
await PublicKeyCredential.signalUnknownCredential({
rpId: "example.com",
credentialId: "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA" // base64url encoded credential ID
});
} else {
// Encourage the user to delete the passkey from the password manager nevertheless.
...
}
}
By calling PublicKeyCredential.signalUnknownCredential() with an RP ID and a
credential ID, the RP can inform the passkey provider that the specified
credential has been removed or does not exist. The passkey provider determines how to handle this signal,
but the associated passkey should be removed so that users don't try to sign in
with a passkey that lacks an associated credential.
This API can be invoked when a passkey-based sign-in has failed because a credential is absent.
This way, the RP can prevent users from attempting to sign in with a passkey that
doesn't have an associated credential. Unlike
signalAllAcceptedCredentials, this method does not require you to pass the entire
list of credential IDs, so use it whenever the user is not authenticated to avoid
revealing the number of passkeys for a given user.
Signal a list of saved credentials
// After a user deletes a passkey or a user is signed in.
// Feature detection
if (PublicKeyCredential.signalAllAcceptedCredentials) {
await PublicKeyCredential.signalAllAcceptedCredentials({
rpId: "example.com",
userId: "M2YPl-KGnA8", // base64url encoded user ID
allAcceptedCredentialIds: [ // A list of base64url encoded credential IDs
"vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA",
...
]
});
}
Use PublicKeyCredential.signalAllAcceptedCredentials() after a user signs in
or manages account settings. You provide a list of all valid credential
IDs for that user. The passkey provider compares this list against its local
storage for that relying party. The passkey provider marks as "hidden" any passkey found in its storage that is not included in the allAcceptedCredentialIds list.
The system no longer offers these hidden passkeys for sign-in or autofill, but they are not immediately deleted permanently, which allows for restoration if necessary.
Conversely, the passkey provider restores passkeys present in allAcceptedCredentialIds that are marked as "hidden".
This lets your website restore passkeys that were hidden in error.
Invoke this API when a user deletes a passkey on the RP and on every sign-in, so the passkey provider can maintain a synchronized list of passkeys.
Signal updated username and display name
// After a user updated their username and/or display name
// or a user is signed in.
// Feature detection
if (PublicKeyCredential.signalCurrentUserDetails) {
await PublicKeyCredential.signalCurrentUserDetails({
rpId: "example.com",
userId: "M2YPl-KGnA8", // base64url encoded user ID
name: "a.new.email.address@example.com", // username
displayName: "J. Doe"
});
} else {
}
By calling PublicKeyCredential.signalCurrentUserDetails() with an RP ID, a
user ID, a username and display name, the RP can inform the passkey provider
about the updated user information. The passkey provider determines how to handle this signal,
but it should update the passkeys the user owns with the new user information.
This API can be invoked when the user's username or display name is updated, and on every sign in, so that the passkey provider can maintain this information synchronized with the server.
Summary
The Signal API helps you build a better passkey experience by eliminating unexpected sign-in failures. The Signal API lets relying parties signal the list of existing credentials and their metadata, so they can keep passkeys on the passkey provider synchronized.
To learn more about passkeys, see Passwordless login with passkeys.