What counts as a breaking change
Knowing what is covered matters more than the version numbers, so it comes first.
Error codesstableA PasskeyErrorCode is never renamed or removed in a minor release. New
codes may be added, so treat an unrecognised code as a generic failure
rather than an impossible state.
PasskeyStorestableMethod signatures do not change in a minor release. A new method would be a major, because every existing implementation would break.
Stored record shapesstablePasskeyCredential and PasskeyUser fields are not removed or retyped in a
minor release. Your database schema is safe across minors.
Wire typesstableThe JSON that travels between passkify/client and the server. Mixed
versions across a deploy must keep working.
Error messagesnot stableWritten for developers and reworded as the documentation improves. Branch
on code, never on message text.
Low-level exportsnot stableparseAuthenticatorData, decodeCBOR and the rest may change shape in a
minor. They are for tooling; the ceremony methods are the API.
rpID is outside versioning entirely
Changing rpID in your own configuration orphans every credential your users
have registered, in any version. It is the one setting with no migration path.
See how passkeys work.
Releases
0.2.0release
Two breaking changes
counter_regression answers 403 rather than 401 — branch on the code, not
the status. RS1 (COSE -65535, RSA with SHA-1) is gone, and a config that
lists it in supportedAlgorithms now throws at construction.
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 fromorigin, conditional create, andhints/extensionspass-through includingprf. - 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: trueand anonCheckhook that return the trace. PasskeyErrorgainedpublicMessageanddetails, so text written for a developer is not sent to an unauthenticated caller. Adapters takeverbose: trueto 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, andmcp, an MCP server whosevalidate_configruns the real validator.passkify/store-conformance, 19 cases including a genuine concurrency race ontakeChallenge, 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.txtand a.mdtwin of every documentation page.
Fixed
- An attestation format passkify cannot verify no longer fails a registration
the site never asked for attestation on.
verifyAttestationran on every registration and threwunsupported_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
undefinedwith the connection open. - Declaration files are emitted for the CommonJS build as
.d.cts, withtypesper condition — the old layout was reported as "masquerading as ESM" for everyrequire().
0.1.0release
Initial release.
Server
PasskeyServerwithstartRegistration,finishRegistration,startAuthenticationandfinishAuthentication.- 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-u2fandapple. MemoryStore, and thePasskeyStoreinterface.- Express middleware and a standards
Requesthandler. - Eager configuration validation for
rpIDandorigin.
Browser
register,login,signInWithAutofill.isSupported,isPlatformAuthenticatorAvailable,isAutofillAvailable.createCredentialandgetAssertionfor use against your own endpoints.- Automatic cancellation of a superseded ceremony.
Both
PasskeyErrorwith stable codes on either side of the wire, includinglast_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:
- 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. - If
supportedAlgorithmslists 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.