@passwordless-id/webauthn

NPM Version npm bundle size NPM Downloads GitHub Repo stars GitHub Sponsors

banner

➤ Demo ➤ Playground

This library greatly simplifies the usage of passkeys by invoking the WebAuthn protocol more conveniently. It is open source, opinionated, dependency-free and minimalistic.

This library is provided by Passwordless.ID, a free public identity provider.

👀 Demos

These demos are plain HTML/JS, not minimized. Just open the sources in your browser if you are curious.

📦 Installation

npm install @passwordless-id/webauthn

The base package contains both client and server side modules. You can import the client submodule or the server depending on your needs.

import {client} from '@passwordless-id/webauthn'
import {server} from '@passwordless-id/webauthn'

Note: the brackets in the import are important!

Alternatives

For browsers, it can be imported using a CDN link in the page, or even inside the script itself.

<script type="module">
  import {client} from src="https://cdn.jsdelivr.net/npm/@passwordless-id/[email protected]/dist/webauthn.min.js"
</script>

Lastly, a CommonJS variant is also available for old Node stacks, to be imported using require('@passwordless-id/webauthn'). It's usage is discouraged though, in favor of the default ES modules.

Note that at least NodeJS 19+ is necessary. (The reason is that previous Node versions had no WebCrypto being globally available, making it impossible to have a "universal build")

🚀 Getting started

There are multiple ways to use and invoke the WebAuthn protocol. What follows is just an example of the most straightforward use case.

Registration

import {client} from '@passwordless-id/webauthn'
await client.register({
  challenge: 'a random string generated by the server',
  user: 'John Doe'
})

By default, this registers a passkey on any authenticator (local or roaming) with preferred user verification. For further options, see → Registration docs

Authentication

import {client} from '@passwordless-id/webauthn'
await client.authenticate({
  challenge: 'a random string generated by the server'
})

By default, this triggers the native passkey selection dialog, for any authenticator (local or roaming) and with preferred user verification. For further options, see → Authentication docs

Verification

import {server} from '@passwordless-id/webauthn'
await server.verifyRegistration(registration, expected)
await server.verifyAuthentication(authentication, expected)

Look at the docs for registration and authentication for the corresponding verification examples. Or simply interact with real-life examples in the Testing Playground.

📃 Changelog

The version 2 introduced breaking changes, different default behavior and different intermediate format. Basically, it's a complete overhaul and to understand "why" this version 2 was made, I recommend reading this blog post. In a very summarized way, it is to enhance support for security keys by default, reflect latest changes in the underlying specs and improve cross-compatibility with other server side libraries.

Some core changes are:

  • Use platform authenticator by default => authenticator selection pops up by default
  • authenticatorType was removed => use hints instead
  • User verification default: required => preferred
  • Timeout: 1 minute => no timeout
  • Response format changed
  • Transports as part of allowCredentials

The docs for the legacy version 1.x are found here