TypeScript helpers for WebAuthn registration and authentication with dedicated server and client entrypoints.
npm install @sourceregistry/node-webauthnimport createWebAuth from "@sourceregistry/node-webauthn/server";
import createWebAuthClient from "@sourceregistry/node-webauthn/client";@sourceregistry/node-webauthn re-exports the server entry:
import createWebAuth from "@sourceregistry/node-webauthn";import createWebAuth from "@sourceregistry/node-webauthn/server";
import createWebAuthClient from "@sourceregistry/node-webauthn/client";
import {generateKeyPairSync} from "node:crypto";
const {privateKey, publicKey} = generateKeyPairSync("ec", {namedCurve: "P-256"});
const server = createWebAuth({
keyPair: {
kid: "main",
private_key: privateKey,
public_key: publicKey
},
issuer: "https://auth.example.com",
rpId: "example.com",
rpName: "Example"
});
const client = createWebAuthClient();
const registrationOptions = server.createRegistrationOptions({
user: {
id: server.toBase64Url("user-123"),
name: "user@example.com",
displayName: "Example User"
}
});
const credential = await client.startRegistration(registrationOptions);
const parsed = server.verifyRegistrationResponse({
expected_challenge: registrationOptions.challenge,
credential_id: credential.id,
client_data_json: credential.client_data_json,
attestation_object: credential.attestation_object,
transports: credential.transports,
client_extension_results: credential.client_extension_results,
origin: "https://example.com",
rp_id: "example.com",
expected_algorithms: registrationOptions.pubKeyCredParams.map(item => item.alg)
});@sourceregistry/node-webauthnRe-exports the server entry.@sourceregistry/node-webauthn/serverNode.js option building, ceremony token, and verification helpers.@sourceregistry/node-webauthn/clientBrowser helpers for JSON conversion, WebAuthn calls, and credential serialization.
- Registration server flow: examples/registration-flow.ts
- Authentication server flow: examples/authentication-flow.ts
- Browser client flow: examples/browser-client.ts
| Area | Status | Notes |
|---|---|---|
| Server-generated registration/authentication options | Strong | createRegistrationOptions(...) and createAuthenticationOptions(...) are the intended entrypoints. |
clientDataJSON validation |
Strong | Checks ceremony type, challenge, origin allowlist, and rejects unsupported cross-origin ceremonies. |
| Authenticator data parsing | Strong | Parses RP ID hash, flags, counters, attested credential data, and extension data. |
| Authentication assertion verification | Strong | Verifies signature, RP/appid hash, UP/UV policy, counter progression, and allowed client extensions. |
| Registration verification core | Strong | Verifies RP ID hash, credential binding, requested algorithm policy, and attestation dispatch. |
| Attestation format coverage | Broad | Supports none, packed, fido-u2f, apple, android-key, android-safetynet, and tpm. |
| Attestation trust policy | Good | Supports none, permissive, and strict trust modes plus trust anchors and metadata hooks. |
| Extension support | Partial | Practical subset today: credProps, appid, appidExclude, and largeBlob. |
| Metadata / revocation | Partial | Metadata hooks exist, but there is no built-in FIDO MDS integration or revocation pipeline yet. |
| Cross-origin / advanced browser edge cases | Limited | Cross-origin ceremonies are intentionally rejected for now. |
| Full spec-tight attestation semantics | Partial | Some format-specific policy checks are still lighter than full ecosystem-grade verification. |
Practical summary:
- This library is strong for common relying-party registration and authentication flows.
- It is not yet fully spec-tight in every attestation and trust-policy edge case.
- The largest remaining gaps are deeper attestation semantics, revocation, and metadata-backed trust.
Creates a reusable server helper with:
generateChallenge(bytes?)createRegistrationOptions(input)createAuthenticationOptions(input)signRegistration(payload)verifyRegistration(token)signAuthentication(payload)verifyAuthentication(token)parseRegistration(input)verifyRegistrationResponse(input)verifyAuthenticationResponse(input)
Returns JSON-safe registration options for the client helper.
Returns JSON-safe authentication options for the client helper.
Validates:
- ceremony type
- challenge
- origin
- RP ID hash
- credential ID match
- requested algorithm policy
- attestation format and trust policy
- registration extension allowlist
Supported attestation formats:
nonepackedfido-u2fappleandroid-keyandroid-safetynettpm
Attestation support status:
| Format | Status | Notes |
|---|---|---|
none |
Strong | Suitable default for easy deployment. |
packed |
Strong | Supports self attestation and certificate-backed validation with optional trust anchors. |
fido-u2f |
Strong | Verified with optional trust anchors. |
apple |
Good | Verifies Apple nonce extension and credential public-key binding. |
android-key |
Partial | Core verification is present, but Android authorization-list policy checks are not exhaustive yet. |
android-safetynet |
Partial | Verifies JWS, nonce, timestamp, and CTS profile, but ecosystem trust/revocation remains lightweight. |
tpm |
Partial | Core certInfo / pubArea validation is present, but TPM certificate/profile checks are not exhaustive yet. |
Registration results include:
credential_idpublic_keyaaguidcounterattestation_formatattestation_typeattestation_trustedattestation_policy_acceptedmetadata_status
Validates:
- ceremony type
- challenge
- origin
- RP ID hash
- signature
- counter progression
- user presence / verification policy
- authentication extension allowlist
Creates browser helpers with:
toCreationOptions(json)toRequestOptions(json)startRegistration(json)startAuthentication(json)serializeRegistrationCredential(credential)serializeAuthenticationCredential(credential)toBase64Url(value)fromBase64Url(value)
Server begin step:
const publicKey = server.createRegistrationOptions({
user: {
id: server.toBase64Url("user-123"),
name: "user@example.com",
displayName: "Example User"
}
});Client step:
const credential = await client.startRegistration(publicKey);Server finish step:
const parsed = server.verifyRegistrationResponse({
expected_challenge: publicKey.challenge,
credential_id: credential.id,
client_data_json: credential.client_data_json,
attestation_object: credential.attestation_object,
transports: credential.transports,
client_extension_results: credential.client_extension_results,
origin: "https://example.com",
rp_id: "example.com",
expected_algorithms: publicKey.pubKeyCredParams.map(item => item.alg)
});Simple format allowlist:
const server = createWebAuth({
keyPair,
rpId: "example.com",
rpName: "Example",
attestation: {
allowed_formats: ["none", "packed"]
}
});Strict trust:
const server = createWebAuth({
keyPair,
rpId: "example.com",
rpName: "Example",
attestation: {
allowed_formats: ["packed", "tpm"],
trust_mode: "strict",
trust_anchors: [rootCertificatePem]
}
});Metadata-backed policy:
const server = createWebAuth({
keyPair,
rpId: "example.com",
rpName: "Example",
attestation: {
allowed_formats: ["android-key", "tpm"],
metadata_provider: {
getEntry({format}) {
if (format === "android-key") {
return {status: "trusted", trusted: true};
}
return null;
}
}
}
});const server = createWebAuth({
keyPair,
rpId: "example.com",
rpName: "Example",
extensions: {
allowed_registration_extensions: ["credProps"],
allowed_authentication_extensions: ["appid", "largeBlob"]
}
});- Compliance notes: docs/spec-notes.md
- Trust model: docs/trust-model.md
The remaining work is intentionally small and incremental so the API can stay easy to use.
- Tighten
android-keyverification with stronger authorization-list checks from the Android key attestation extension. - Tighten
tpmverification with more complete certificate/profile validation and TPM-specific policy checks. - Strengthen
android-safetynettrust handling with clearer certificate-policy validation and optional revocation hooks. - Add optional FIDO Metadata Service integration behind the existing
metadata_providerstyle trust model. - Add optional revocation checking for attestation certificate chains.
- Expand extension semantics only where they matter for relying-party policy, instead of trying to support every extension by default.
- Add more conformance-style negative fixtures for attestation and trust-policy edge cases.
- The default API is intentionally small.
- Trust evaluation is optional by default and can be tightened with
trust_mode,trust_anchors, andmetadata_provider.