Changelog

Release history, and the compatibility promise for each part of the API.

What counts as a breaking change

Knowing what is covered matters more than the version numbers, so it comes first.

Error codesstable
PasskeyStorestable
Stored record shapesstable
Wire typesstable
Error messagesnot stable
Low-level exportsnot stable

Releases

0.2.0release

The verification path is pure WebCrypto

No node: built-in is imported anywhere a ceremony can reach, which is what makes the Cloudflare Workers, Deno and Vercel Edge support real rather than aspirational. A test walks every source file on each run and fails if one appears. X.509 handling is written here rather than delegated, and ECDSA signatures are converted from DER by a deliberately strict parser — a lenient one there is a signature-malleability bug.

Server

  • WebAuthn Level 3: the three signal methods, getClientCapabilities(), Related Origin Requests with the published file derived from origin, conditional create, and hints/extensions pass-through including prf.
  • Adapters for Next.js, Hono, Fastify, SvelteKit, Remix and Cloudflare Workers.
  • Stores for Postgres, Prisma, Redis, MongoDB and SQLite, each taking the driver you already have so none of them becomes a dependency.
  • A check registry the verifiers index into, plus explain: true and an onCheck hook that return the trace.
  • PasskeyError gained publicMessage and details, so text written for a developer is not sent to an unauthenticated caller. Adapters take verbose: true to restore the old behaviour in development.

Browser

  • passkify/react: useRegister, useLogin, usePasskeyAutofill, usePasskeys, usePasskeySupport.
  • Client APIs for the credential-management routes that previously existed only on the server: listPasskeys, renamePasskey, deletePasskey, syncPasskeys.

Tooling

  • npx passkify — init, doctor, skills install, and mcp, an MCP server whose validate_config runs the real validator.
  • passkify/store-conformance, 19 cases including a genuine concurrency race on takeChallenge, so a read-then-delete store fails rather than silently permitting replay.
  • passkify/testing, the virtual authenticator the library's own suite uses.
  • /llms.txt, /llms-full.txt and a .md twin of every documentation page.

Fixed

  • An attestation format passkify cannot verify no longer fails a registration the site never asked for attestation on. verifyAttestation ran on every registration and threw unsupported_feature (500) for any format without a verifier, so TPM-backed Windows Hello could not register at all.
  • An oversized request body returns 413 and is drained rather than left resolving to undefined with the connection open.
  • Declaration files are emitted for the CommonJS build as .d.cts, with types per condition — the old layout was reported as "masquerading as ESM" for every require().

0.1.0release

Initial release.

Server

  • PasskeyServer with startRegistration, finishRegistration, startAuthentication and finishAuthentication.
  • Credential management: listCredentials, renameCredential, deleteCredential.
  • Full WebAuthn §7.1 and §7.2 verification, 29 checks across the two ceremonies.
  • Hand-written CBOR decoder, COSE key parsing, and signature verification for ES256/384/512, RS256/384/512, RS1, PS256/384/512 and EdDSA.
  • Attestation verification for none, packed, fido-u2f and apple.
  • MemoryStore, and the PasskeyStore interface.
  • Express middleware and a standards Request handler.
  • Eager configuration validation for rpID and origin.

Browser

  • register, login, signInWithAutofill.
  • isSupported, isPlatformAuthenticatorAvailable, isAutofillAvailable.
  • createCredential and getAssertion for use against your own endpoints.
  • Automatic cancellation of a superseded ceremony.

Both

  • PasskeyError with stable codes on either side of the wire, including last_credential (409) when removing an account's only passkey is refused.
  • Zero runtime dependencies. ESM and CommonJS builds.
  • 92 tests, most of them tampered responses driven by a virtual authenticator.

Upgrading

0.1.0 to 0.2.0. Two things to check, neither of which touches your database:

  1. If any code branches on the HTTP status of a counter regression, move it to error.code === 'counter_regression'. The status changed from 401 to 403.
  2. If supportedAlgorithms lists RS1 (-65535), remove it. The server now refuses to construct rather than accepting a SHA-1 signature.

Stored PasskeyCredential and PasskeyUser records are unchanged, as are the wire types, so a mixed deploy keeps working while it rolls.