webauthn

NPM: @hexagon\webauthn | Deno.land: webauthn

Slim Webauthn library with ES6, Deno and Node (>=16) support. Heavily based on fido2-lib.

Currently in pre-release

Node.js CI Deno CI npm version NPM Downloads MIT License jsdelivr

Example for both Deno and Node available at github.com/Hexagon/webauthn-skeleton

Features

Specific to @hexagon/webauthn

  • Supports Deno and recent versions of Node (>=16)
  • Pure ESM code base
  • Bundled distributable, no remote dependencies

Inherited from fido2-lib

  • Works with Windows Hello, Android lock screen, Yubikeys
  • Attestation formats: packed, tpm, android-safetynet, fido-u2f, none
  • Convenient API for adding more attestation formats
  • Convenient API for adding extensions
  • Metadata service (MDS) support enables authenticator root of trust and authenticator metadata
  • Support for multiple simultaneous metadata services (e.g. FIDO MDS 1 & 2)
  • Crypto families: ECDSA, RSA
  • x509 cert parsing, support for FIDO-related extensions, and NIST Public Key Interoperability Test Suite (PKITS) chain validation (from pki.js)
  • Returns parsed and validated data, along with extra audit data for risk engines

Installation

Deno

Import dist/webauthn.js using your favorite metod. The module is available at deno.land/x/webauthn, jsdelivr, npm, unpkg etc.

import { Webauthn } from "https://cdn.jsdelivr.net/gh/hexagon/webauthn@0/dist/webauthn.js";

// ...

Node.js

npm install @hexagon/webauthn --save

// ESM Import ...
import { Webauthn } from "@hexagon/webauthn";

// ... or CommonJS
const { Webauthn } = await import("@hexagon/webauthn");

Usage

Examples

All examles assumes you have imported webauthn as described under ‘Installation’.

@hexagon/webauthn uses the same interface as fido2-lib

Instantiate Library (Simple):

// create a new instance of the library
var f2l = new Webauthn();

Instantiate Library (Complex):

// could also use one or more of the options below,
// which just makes the options calls easier later on:
var f2l = new Webauthn({
    timeout: 42,
    rpId: "example.com",
    rpName: "ACME",
    rpIcon: "https://example.com/logo.png",
    challengeSize: 128,
    attestation: "none",
    cryptoParams: [-7, -257],
    authenticatorAttachment: "platform",
    authenticatorRequireResidentKey: false,
    authenticatorUserVerification: "required"
});

Registration:

var registrationOptions = await f2l.attestationOptions();

// make sure to add registrationOptions.user.id
// save the challenge in the session information...
// send registrationOptions to client and pass them in to `navigator.credentials.create()`...
// get response back from client (clientAttestationResponse)

var attestationExpectations = {
    challenge: "33EHav-jZ1v9qwH783aU-j0ARx6r5o-YHh-wd7C6jPbd7Wh6ytbIZosIIACehwf9-s6hXhySHO-HHUjEwZS29w",
    origin: "https://localhost:8443",
    factor: "either"
};
var regResult = await f2l.attestationResult(clientAttestationResponse, attestationExpectations); // will throw on error

// registration complete!
// save publicKey and counter from regResult to user's info for future authentication calls

Authentication:

var authnOptions = await f2l.assertionOptions();

// add allowCredentials to limit the number of allowed credential for the authentication process. For further details refer to webauthn specs: (https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-allowcredentials).
// save the challenge in the session information...
// send authnOptions to client and pass them in to `navigator.credentials.get()`...
// get response back from client (clientAssertionResponse)

var assertionExpectations = {
    // Remove the following comment if allowCredentials has been added into authnOptions so the credential received will be validate against allowCredentials array.
    // allowCredentials: [{
    //     id: "lTqW8H/lHJ4yT0nLOvsvKgcyJCeO8LdUjG5vkXpgO2b0XfyjLMejRvW5oslZtA4B/GgkO/qhTgoBWSlDqCng4Q==",
    //     type: "public-key",
    //     transports: ["usb"]
    // }],
    challenge: "eaTyUNnyPDDdK8SNEgTEUvz1Q8dylkjjTimYd5X7QAo-F8_Z1lsJi3BilUpFZHkICNDWY8r9ivnTgW7-XZC3qQ",
    origin: "https://localhost:8443",
    factor: "either",
    publicKey: "-----BEGIN PUBLIC KEY-----\n" +
        "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERez9aO2wBAWO54MuGbEqSdWahSnG\n" +
        "MAg35BCNkaE3j8Q+O/ZhhKqTeIKm7El70EG6ejt4sg1ZaoQ5ELg8k3ywTg==\n" +
        "-----END PUBLIC KEY-----\n",
    prevCounter: 362
};
var authnResult = await f2l.assertionResult(clientAssertionResponse, assertionExpectations); // will throw on error

// authentication complete!

Full demo for both Deno and Node available at github.com/Hexagon/webauthn-skeleton/tree/server/deno

Contributing

See Contribution Guide for general guidelines.

Development

Command Description
deno task test Run deno tests
deno task test:dist Run deno tests against distributable
deno task coverage Run deno tests and display coverage
deno lint Lint code base
npm run typings Build typings (using tsc)
npm run docs Build docs (using jsdoc)
npm run test:dist Run node tests (against distributable)
npm run test Run node tests (against against pure library, special case as dist is used normally)
deno task build Run all sorts of checks, both node and deno, then builds the bundle

File structure

Path Description
/lib Source code base folder
/lib/attestation/ Attestation plug-ins
/lib/webauthn.js Entrypoint
/lib/toolbox.js External dependencies
/test Tests (supporting both Node and Deno)
/docs Documentation

Dependencies

For current dependencies, see /import_map.json (used by Deno) or /package.json (used by Node)

Contributors

The underlying code is heavily based on github.com/webauthn-open-source/fido2-lib

License

MIT