A library for performing FIDO 2.0 / WebAuthn server functionality
This library contains all the functionality necessary for implementing a full FIDO2 / WebAuthn server. It intentionally does not implement any kind of networking protocol (e.g. - REST endpoints) so that it can remain independent of any messaging protocols.
There are four primary functions:
There is also an extension point for adding new attestation formats.
Full documentation can be found here.
For working examples see OWASP Single Sign-On and / or webauthn.io
require
) and ESM (import
) nativelynpm install fido2-lib --save
const { Fido2Lib } = require("fido2-lib");
import { Fido2Lib } from "fido2-lib";
Import dist/main.js
from a trusted source. Below is only an example, using the official deno.land repository.
It is recommended to enable integrity checking.
import { Fido2Lib } from "https://deno.land/x/fido2@$VERSION/dist/main.js";
Don't forget to replace $VERSION
with the specific version. You can find the latest version by checking the redirection of deno.land/x/fido2/dist/main.js and deno.land/x/fido2/types/main.d.ts.
Instantiate Library (Complex):
// could also use one or more of the options below,
// which just makes the options calls easier later on:
const f2l = new Fido2Lib({
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:
const registrationOptions = await f2l.attestationOptions();
// make sure to add registrationOptions.user.id and registrationOptions.user.name
// 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)
const attestationExpectations = {
challenge: "33EHav-jZ1v9qwH783aU-j0ARx6r5o-YHh-wd7C6jPbd7Wh6ytbIZosIIACehwf9-s6hXhySHO-HHUjEwZS29w",
origin: "https://localhost:8443",
factor: "either"
};
const 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:
const 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)
const 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
};
const authnResult = await f2l.assertionResult(clientAssertionResponse, assertionExpectations); // will throw on error
// authentication complete!
For a real-life example, refer to OWASP Single Sign-On.
Generally v3 is assumed to be completely compatible with v2 - compatibility should have increased. As many inner workings have been changed, please verify that your application still works with v3 and report issues, if you newly encounter bugs.
It's recommended to have both Deno (>=1.20) and Node 16-18 available to be able to run all checks and tests.
Please run npm run lint
, npm run test
and deno task test
before committing, to make sure every test and check passes.
See package.json for available npm scripts, and deno.jsonc for available Deno tasks.
Make sure to add tests if you add new features.
Important: Do not stage/commit dist/main.js
and dist/main.cjs
. These are generated and committed automatically by the CI-pipeline.
When adding, removing or updating dependencies, start out with npm as usual. Then update import_map.json
to the same versions shown by npm list
, and run deno task update-deps
to update the Deno lock-file.
When you're finished with the changes, create a pull request.
Work for this project was supported by Adam Power.