Releases: MasterKale/SimpleWebAuthn
v13.0.0 - The one where they share a type
Hot on the heels of the last major release, v13 introduces support for registration hints! Refined types and improved attestation trust anchor verification are also included. Last but not least, we say goodbye to one of the project's packages for better docs and fewer dependencies to install. Read on for more information, including refactor advice for dealing with the retirement of @simplewebauthn/types.
Changes:
- [server] A new
preferredAuthenticatorType
argument can be set when callinggenerateRegistrationOptions()
to generate options that encourage the browser to direct the user to register one of three types of authenticators:'securityKey'
,'localDevice'
, or'remoteDevice'
(a.k.a. opinionated WebAuthn hints support) (#653) - [browser]
startRegistration()
will recognizehints
if specified inoptionsJSON
(#652) - [server] Attestation verification now recognizes intermediate certificates as trust anchors (#650)
- [browser] [server] The types previously maintained in the types package are now included within the browser and server packages. See Breaking Changes below for more info (#655)
Breaking Changes
@typescript/types is being retired.
Its types will now be included directly in @simplewebauthn/browser and @simplewebauthn/server.
To refactor existing imports from /types, simply import them from /browser or /server instead:
Before:
import type {
AuthenticationResponseJSON,
RegistrationResponseJSON,
WebAuthnCredential,
} from '@simplewebauthn/types'; // <--
After:
import type {
AuthenticationResponseJSON,
RegistrationResponseJSON,
WebAuthnCredential,
} from '@simplewebauthn/server'; // <--
[server] attestationType
no longer accepts 'indirect'
The benefits of indirect attestation are too minimal to be useful for Relying Parties. In practice it is almost never used over ignoring the concept completely with 'none'
or needing to be intentional and setting 'direct'
.
RP's that have been specifying attestationType: 'indirect'
when calling generateRegistrationOptions()
will need to refactor their code to either omit attestationType
(generateRegistrationOptions()
will default to attestationType: 'none'
) or set attestationType: 'direct'
instead:
Before:
const options = await generateRegistrationOptions({
// ...
attestationType: 'indirect'
});
After:
const options = await generateRegistrationOptions({
// ...
});
-or-
const options = await generateRegistrationOptions({
// ...
attestationType: 'direct'
});
v12.0.0 - The one that claims a JSR scope
All SimpleWebAuthn packages are now available for installation from the JavaScript Registry (JSR)! JSR is an "open-source package registry for modern JavaScript and TypeScript" - you can read more about this new package registry and its ESM-centric capabilities here.
All packages in v12.0.0 are functionally identical to v11.0.0! And JSR package hosting is in addition to existing package hosting on NPM. Nothing changes about package installation via npm install
. Read on for more information.
Packages
- @simplewebauthn/[email protected]
- @simplewebauthn/[email protected]
- @simplewebauthn/[email protected]
Changes
- [browser] [server] [types] All packages can now be installed from JSR wherever JSR imports are supported (#634)
- [browser] Deno projects using frameworks like Fresh can now import and use @simplewebauthn/browser (#634)
To install from JSR, use npx jsr add @simplewebauthn/...
or deno add jsr:@simplewebauthn/...
depending on which package manager is available.
Projects using npm
for package management:
npx jsr add @simplewebauthn/browser
npx jsr add @simplewebauthn/server
npx jsr add @simplewebauthn/types
Projects using deno
for package management:
deno add jsr:@simplewebauthn/browser
deno add jsr:@simplewebauthn/server
deno add jsr:@simplewebauthn/types
Projects using HTTPS modules via deno.land/x:
v12.0.0 officially deprecates importing SimpleWebAuthn from deno.land/x. See Breaking Changes below for refactor guidance.
Breaking Changes
Importing SimpleWebAuthn packages from "https://deno.land/x/simplewebauthn/..."
URLs is no longer supported. Please use Deno's native support for JSR imports instead, available in projects running Deno v1.42 and higher.
Before:
import { generateAuthenticationOptions } from 'https://deno.land/x/simplewebauthn/deno/server.ts';
After:
import { generateAuthenticationOptions } from 'jsr:@simplewebauthn/server';
Alternatively, use deno add
to install these packages from JSR:
# Deno v1.42 and higher
deno add jsr:@simplewebauthn/server
import { generateAuthenticationOptions } from '@simplewebauthn/server';
v11.0.0 - The one that auto-registers
Say hello to support for automatic passkey registration, support for valid conditional UI <input>
elements stashed away in web components, and to the new WebAuthnCredential
type that modernizes some logic within.
There are some breaking changes in this release! Please see Breaking Changes below for refactor guidance.
Packages
- @simplewebauthn/[email protected]
- @simplewebauthn/[email protected]
- @simplewebauthn/[email protected]
Changes
- [browser] [server] A new
useAutoRegister
argument has been added tostartRegistration()
to support attempts to automatically register passkeys for users who just completed non-passkey auth.verifyRegistrationResponse()
has gained a newrequireUserPresence
option that can be set tofalse
when verifying responses fromstartRegistration({ useAutoRegister: true, ... })
(#623) - [browser] A new
verifyBrowserAutofillInput
argument has been added tostartAuthentication()
to disable throwing an error when a correctly configured<input>
element cannot be found (but perhaps a valid one is present in a web component shadow's DOM) (#621) - [server] [types] The
AuthenticatorDevice
type has been renamed toWebAuthnCredential
and has had its properties renamed. The return value out ofverifyRegistrationResponse()
and corresponding inputs intoverifyAuthenticationResponse()
have been updated accordingly. See Breaking Changes below for refactor guidance (#625) - [server]
verifyRegistrationResponse()
now verifies that the authenticator data AAGUID matches the leaf cert'sid-fido-gen-ce-aaguid
extension AAGUID when it is present (#609) - [server] TPM attestation verification recognizes the corrected TPM manufacturer identifier for IBM (#610)
- [server] Types for the defunct authenticator extensions
uvm
anddpk
have been removed (#611)
Breaking Changes
[browser] Positional arguments in startRegistration()
and startAuthentication()
have been replaced by a single object
Property names in the object match the names of the previously-positional arguments. To update existing implementations, wrap existing options in an object with corresponding properties:
Before:
startRegistration(options);
startAuthentication(options, true);
After:
startRegistration({ optionsJSON: options });
startAuthentication({ optionsJSON: options, useBrowserAutofill: true });
[server] [types] The AuthenticatorDevice
type has been renamed to WebAuthnCredential
AuthenticatorDevice.credentialID
and AuthenticatorDevice.credentialPublicKey
have been shortened to WebAuthnCredential.id
and WebAuthnCredential.publicKey
respectively.
verifyRegistrationResponse()
has been updated accordingly to return a new credential
value of type WebAuthnCredential
. Update code that stores credentialID
, credentialPublicKey
, and counter
out of verifyRegistrationResponse()
to store credential.id
, credential.publicKey
, and credential.counter
instead:
Before:
const { registrationInfo } = await verifyRegistrationResponse({...});
storeInDatabase(
registrationInfo.credentialID,
registrationInfo.credentialPublicKey,
registrationInfo.counter,
body.response.transports,
);
After:
const { registrationInfo } = await verifyRegistrationResponse({...});
storeInDatabase(
registrationInfo.credential.id,
registrationInfo.credential.publicKey,
registrationInfo.credential.counter,
registrationInfo.credential.transports,
);
Update calls to verifyAuthenticationResponse()
to match the new credential
argument that replaces the authenticator
argument:
Before:
import { AuthenticatorDevice } from '@simplewebauthn/types';
const authenticator: AuthenticatorDevice = {
credentialID: ...,
credentialPublicKey: ...,
counter: 0,
transports: [...],
};
const verification = await verifyAuthenticationResponse({
// ...
authenticator,
});
After:
import { WebAuthnCredential } from '@simplewebauthn/types';
const credential: WebAuthnCredential = {
id: ...,
publicKey: ...,
counter: 0,
transports: [...],
};
const verification = await verifyAuthenticationResponse({
// ...
credential,
});
v10.0.1
v10.0.0 - The one that goes up to 20
Thanks for everything, Node 16 and Node 18, but it's time to move on! The headlining change of this
release is the targeting of Node LTS v20+ as the minimum Node runtime. Additional developer-centric
quality-of-life changes have also been made in the name of streamlining use of SimpleWebAuthn on
both the back end and front end.
This release is packed with updates, so buckle up! Refactor advice for breaking changes is, as
always, offered below.
Packages
- @simplewebauthn/[email protected]
- @simplewebauthn/[email protected]
- @simplewebauthn/[email protected]
Changes
- [server] The minimum supported Node version has been raised to Node v20
(#531) - [server]
user.displayName
now defaults to an empty string if a value is not specified for
userDisplayName
when callinggenerateRegistrationOptions()
(#538) - [browser] The
browserSupportsWebAuthnAutofill()
helper will no longer break in environments
in whichPublicKeyCredential
is not present
(#557, with thanks to @clarafitzgerald)
Breaking Changes
- [server] The following breaking changes were made in PR
#529:generateRegistrationOptions()
now expectsBase64URLString
for excluded credential IDsgenerateAuthenticationOptions()
now expectsBase64URLString
for allowed credential IDscredentialID
returned from response verification methods is now aBase64URLString
AuthenticatorDevice.credentialID
is now aBase64URLString
isoBase64URL.isBase64url()
is now calledisoBase64URL.isBase64URL()
- [browser, server] The following breaking changes were made in PR
#552:generateRegistrationOptions()
now accepts an optionalUint8Array
instead of astring
for
userID
isoBase64URL.toString()
andisoBase64URL.fromString()
have been renamedgenerateRegistrationOptions()
will now generate random user IDsuser.id
is now treated like a base64url string instartRegistration()
userHandle
is now treated like a base64url string instartAuthentication()
- [server]
rpID
is now a required argument when callinggenerateAuthenticationOptions()
(#555)
[server] generateRegistrationOptions()
now expects Base64URLString
for excluded credential IDs
The isoBase64URL
helper can be used to massage Uint8Array
credential IDs into base64url strings:
Before
const opts = await generateRegistrationOptions({
// ...
excludeCredentials: devices.map((dev) => ({
id: dev.credentialID, // type: Uint8Array
type: 'public-key',
transports: dev.transports,
})),
});
After
import { isoBase64URL } from '@simplewebauthn/server/helpers';
const opts = await generateRegistrationOptions({
// ...
excludeCredentials: devices.map((dev) => ({
id: isoBase64URL.fromBuffer(dev.credentialID), // type: string
transports: dev.transports,
})),
});
The type
argument is no longer needed either.
[server] generateAuthenticationOptions()
now expects Base64URLString
for allowed credential IDs
Similarly, the isoBase64URL
helper can also be used during auth to massage Uint8Array
credential
IDs into base64url strings:
Before
const opts = await generateAuthenticationOptions({
// ...
allowCredentials: devices.map((dev) => ({
id: dev.credentialID, // type: Uint8Array
type: 'public-key',
transports: dev.transports,
})),
});
After
import { isoBase64URL } from '@simplewebauthn/server/helpers';
const opts = await generateAuthenticationOptions({
// ...
allowCredentials: devices.map((dev) => ({
id: isoBase64URL.fromBuffer(dev.credentialID), // type: Base64URLString (a.k.a string)
transports: dev.transports,
})),
});
The type
argument is no longer needed either.
[server] credentialID
returned from response verification methods is now a Base64URLString
It is no longer necessary to manually stringify credentialID
out of response verification methods:
Before
import { isoBase64URL } from '@simplewebauthn/server/helpers';
// Registration
const { verified, registrationInfo } = await verifyRegistrationResponse({ ... });
if (verified && registrationInfo) {
const { credentialID } = registrationInfo;
await storeInDatabase({ credIDString: isoBase64URL.fromBuffer(credentialID), ... });
}
// Authentication
const { verified, authenticationInfo } = await verifyAuthenticationResponse({ ... });
if (verified && authenticationInfo) {
const { newCounter, credentialID } = authenticationInfo;
dbAuthenticator.counter = authenticationInfo.newCounter;
await updateCounterInDatabase({
credIDString: isoBase64URL.fromBuffer(credentialID),
newCounter,
});
}
After
// Registration
const { verified, registrationInfo } = await verifyRegistrationResponse({ ... });
if (verified && registrationInfo) {
const { credentialID } = registrationInfo;
await storeInDatabase({ credIDString: credentialID, ... });
}
// Authentication
const { verified, authenticationInfo } = await verifyAuthenticationResponse({ ... });
if (verified && authenticationInfo) {
const { newCounter, credentialID } = authenticationInfo;
dbAuthenticator.counter = authenticationInfo.newCounter;
await updateCounterInDatabase({ credIDString: credentialID, newCounter });
}
[server] AuthenticatorDevice.credentialID
is now a Base64URLString
Calls to verifyAuthenticationResponse()
will need to be updated to encode the credential ID to a
base64url string:
Before
const verification = await verifyAuthenticationResponse({
// ...
authenticator: {
// ...
credentialID: credIDBytes,
},
});
After
import { isoBase64URL } from '@simplewebauthn/server/helpers';
const verification = await verifyAuthenticationResponse({
// ...
authenticator: {
// ...
credentialID: isoBase64URL.fromBuffer(credIDBytes),
},
});
[server] isoBase64URL.isBase64url()
is now called isoBase64URL.isBase64URL()
Note the capitalization change from "url" to "URL" in the method name. Update calls to this method
accordingly.
[server] generateRegistrationOptions()
will now generate random user IDs
[browser] user.id
is now treated like a base64url string in startRegistration()
[browser] userHandle
is now treated like a base64url string in startAuthentication()
A random identifier will now be generated when a value is not provided for the now-optional userID
argument when calling generateRegistrationOptions()
. This identifier will be base64url-encoded
string of 32 random bytes. RPs that wish to take advantage of this can simply omit this
argument.
Additionally, startRegistration()
will base64url-decode user.id
before calling WebAuthn. During
auth startAuthentication()
will base64url-encode userHandle
in the returned credential. This
should be a transparent change for RP's that simply feed @simplewebauthn/server options output
into the corresponding @simplewebauthn/browser methods.
However, RP's that wish to continue generating their own user identifiers will need to take
additional steps to ensure they get back user IDs in the expected format after authentication.
Before (SimpleWebAuthn v9)
// @simplewebauthn/server v9.x
const opts = generateRegistrationOptions({
// ...
userID: 'randomUserID',
});
// @simplewebauthn/browser v9.x
const credential = await startAuthentication(...);
sendToServer(credential);
// @simplewebauthn/server v9.x
const credential = await receiveFromBrowser();
console.log(
credential.response.userhandle, // 'randomUserID'
);
After (SimpleWebAuthn v10)
// @simplewebauthn/server v10.x
import { isoUint8Array } from '@simplewebauthn/server/helpers';
const opts = generateRegistrationOptions({
// ...
userID: isoUint8Array.fromUTF8String('randomUserID'),
});
// @simplewebauthn/browser v10.x
const credential = await startAuthentication(...);
sendToServer(credential);
// @simplewebauthn/server v10.x
import { isoBase64URL } from '@simplewebauthn/server/helpers';
const credential = await receiveFromBrowser();
console.log(
isoBase64URL.toUTF8String(credential.response.userhandle), // 'randomUserID'
);
[server] isoBase64URL.toString()
and isoBase64URL.fromString()
have been renamed
The method names have been updated to reflect the use of UTF-8 string encoding:
Before:
const foo = isoBase64URL.toString('...');
const bar = isoBase64URL.fromString('...');
After:
const foo = isoBase64URL.toUTF8String('...');
const bar = isoBase64URL.fromUTF8String('...');
[server] rpID
is now a required argument when calling generateAuthenticationOptions()
Update calls to this method to specify the same rpID
as passed into
generateRegistrationOptions()
:
Before
generateRegistrationOptions({ rpID: 'example.com', ... });
generateAuthenticationOptions();
After
generateRegistrationOptions({ rpID: 'example.com', ... });
generateAuthenticationOptions({ rpID: 'example.com' });
v9.0.3
Packages
- @simplewebauthn/[email protected]
Changes
- [server] Fixed
"Cannot find module 'cbor-x/index-no-eval' or its corresponding type declarations"
build errors when transpiling TypeScript projects using @simplewebauthn/server (#521)
v9.0.2
Packages
- @simplewebauthn/[email protected]
Changes
- [server] Improved support for Next.js Edge runtime (#518, with thanks to @balazsorban44)
v9.0.1
Packages
- @simplewebauthn/[email protected]
- @simplewebauthn/[email protected]
- @simplewebauthn/[email protected]
Changes
v9.0.0 - The one in which 11 characters were saved
Packages
- @simplewebauthn/[email protected]
- @simplewebauthn/[email protected]
- @simplewebauthn/[email protected]
Changes
- [types] The
@simplewebauthn/typescript-types
package has been renamed to
@simplewebauthn/types
(#508)
Breaking Changes
- Any reference to
@simplwebauthn/typescript-types
will need to be replaced with the new package name@simplewebauthn/types
:
Before:
import { ... } from '@simplwebauthn/typescript-types';
After:
$> npm uninstall @simplewebauthn/typescript-types
$> npm install -D @simplewebauthn/types
import { ... } from '@simplwebauthn/types';
v8.3.7
Packages
- @simplewebauthn/[email protected]
- @simplewebauthn/[email protected]
Changes
- [browser] The
WebAuthnError
class can now be imported from@simplewebauthn/browser
for simpler error detection and handling when callingstartRegistration()
andstartAuthentication()
(#505, with thanks to @zoontek) - [server] The
COSEPublicKeyEC2
,COSEPublicKeyOKP
, andCOSEPublicKeyRSA
types can now be imported from@simplwebauthn/server/helpers
to help type possible return values fromdecodeCredentialPublicKey()
(#504, with thanks to @mmv08) - [server] Custom challenge strings passed to
generateRegistrationOptions()
will now be treated as UTF-8 strings to align with the existing behavior ofgenerateAuthenticationOptions()
(#507)