Webauthn expecting userHandle web-auth/webauthn-lib v5.0.0

Updated: Jan 29, 2025

Webauthn expecting userHandle web-auth/webauthn-lib v5.0.0

WebAuthn is a modern standard for passwordless authentication that relies on public key cryptography and user verification methods such as biometrics or security keys. The userHandle is a required parameter in the WebAuthn protocol that identifies the user during the registration and authentication process.

The userHandle is a string that represents the user's identity, and it can be either a displayName or a publicKeyRp value. The displayName is an optional human-readable name for the user, while the publicKeyRp is a required identifier for the origin or the relying party that is requesting the authentication.

When a user registers a new credential (such as a security key or a biometric), the browser generates a random userHandle based on the publicKeyRp and the displayName. The userHandle is then sent to the server along with the other registration data, such as the public key and the attestation statement.

During the authentication process, the browser sends the userHandle and the challenge to the server, which then responds with a clientDataJSON and a authenticatorData. The clientDataJSON contains the publicKeyRp, the userHandle, and other information related to the request. The authenticatorData contains the cryptographic proof generated by the authenticator (such as a security key or a biometric sensor).

The webauthn-lib is a popular library for implementing the WebAuthn protocol in Node.js. Version 5.0.0 of this library includes support for the userHandle parameter. To use this parameter, you need to pass it as an option to the register or login methods of the library.

Here's an example of how to use the userHandle parameter with the webauthn-lib library:

const WebAuth = require('webauthn-lib');

async function registerCredential(publicKey, displayName, userHandle) {
  const credential = await WebAuth.create({
    publicKey,
    user: {
      id: userHandle,
      name: displayName,
    },
  });

  const attestation = await WebAuth.authenticate(credential);
  const registration = await WebAuth.register(credential, attestation);

  return registration;
}

async function loginCredential(publicKey, userHandle) {
  const credential = await WebAuth.create({
    publicKey,
    user: {
      id: userHandle,
    },
  });

  const attestation = await WebAuth.authenticate(credential);
  const authentication = await WebAuth.login(credential, attestation);

  return authentication;
}

In this example, the registerCredential and loginCredential functions take a publicKey, a displayName, and a userHandle as arguments. The userHandle is then passed as an option to the WebAuth.create method when creating a new credential, and it is also passed as an argument to the WebAuth.authenticate method when authenticating the credential.

By using the userHandle parameter, you can ensure that the same user is identified consistently across different authentication requests, even if their display name or other identifying information changes. This can help improve security and reduce the risk of account takeover attacks.