banner

Passwordless.ID /

Webauthn Playground

This is a playground for the webauthn wrapper library. Nothing here is sent to any server, everything runs locally.

Registration

A username, email or other identifier

A server-side randomly generated nonce, base64url encoded.
Which device to use as authenticator.
Whether a biometric/PIN check is required or not. This filters out security keys not having this capability.
A "discoverable" credential can be selected using `authenticate(...)` without providing credential IDs. Instead, a native pop-up will appear for user selection. This may have an impact on the "passkeys" user experience and syncing behavior of the key.
Number of milliseconds the user has to respond to the biometric/PIN check.

If enabled, the device attestation and clientData will be provided as base64 encoded binary data. Note that this may impact the authenticator information available or the UX depending on the platform.

await client.register("{{registration.username}}", "{{registration.challenge}}", {{registration.options}})
Register device
{{registration.result ?? '...'}}

And on the server side, verifying the registration leads to:

await server.verifyRegistration(registration, {challenge: "{{registration.challenge}}", origin: "{{origin}}"})

Resulting into:

{{registration.parsed ?? '...'}}

At this point, you should store the `credential` and associate it with the user account. You will need it later to verify authentication attempts.

Authentication

A server-side randomly generated nonce, base64url encoded.
Which device to use as authenticator.
Number of milliseconds the user has to respond to the biometric/PIN check.
Whether a biometric/PIN check is required or not. This filters out security keys not having this capability.
webauthn.authenticate(["{{authentication.credentialId}}"], "{{authentication.challenge}}", {{authentication.options}})
Login
{{authentication.result ?? '...'}}

And on the server side, verifying the authentication leads to:

const credentialKey = {
    id: "{{registration?.parsed?.credential?.id ?? '...'}}",
    publicKey: "{{registration?.parsed?.credential?.publicKey ?? '...'}}",
    algorithm: "{{registration?.parsed?.credential?.algorithm ?? '...'}}"
}

const expected = {
    challenge: "{{authentication?.challenge ?? '...'}}",
    origin: "{{origin}}",
    userVerified: {{authentication?.options?.userVerification === 'required'}},
    counter: -1
}

const verified = await server.verifyAuthentication(res, credentialKey, expected)
        

Resulting into:

{{authentication.parsed ?? '...'}}

Please note that the parsed result is returned for the sake of completeness. It is already verified, including the signature.

Signature validation

This part is mainly for debugging purposes or validation.


The algorithm used for the public key created during registration.
The public key created during registration.

{{parseAuthData(verification.authenticatorData)}}
{{parseClientData(verification.clientData)}}

signature = sign(algorithm, publicKey, authenticatorData + sha256(clientData))

Verify
Signature is {{verification.isValid ? 'valid' : 'invalid'}}