Skip to content

Releases: MasterKale/SimpleWebAuthn

v13.0.0 - The one where they share a type

09 Dec 02:43
6b27e92
Compare
Choose a tag to compare

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 calling generateRegistrationOptions() 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 recognize hints if specified in optionsJSON (#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

25 Nov 07:08
5b3422b
Compare
Choose a tag to compare

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

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

13 Oct 16:21
1b06f47
Compare
Choose a tag to compare

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

Changes

  • [browser] [server] A new useAutoRegister argument has been added to startRegistration() to support attempts to automatically register passkeys for users who just completed non-passkey auth. verifyRegistrationResponse() has gained a new requireUserPresence option that can be set to false when verifying responses from startRegistration({ useAutoRegister: true, ... }) (#623)
  • [browser] A new verifyBrowserAutofillInput argument has been added to startAuthentication() 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 to WebAuthnCredential and has had its properties renamed. The return value out of verifyRegistrationResponse() and corresponding inputs into verifyAuthenticationResponse() 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's id-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 and dpk 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

23 Jul 04:47
a4a178c
Compare
Choose a tag to compare

Packages

Changes

  • [server] isoCrypto.verify() now has better support for signature verification with ECC public keys using P-256, P-385, and P-521 curves (#594, with thanks to @nlordell)

v10.0.0 - The one that goes up to 20

12 Apr 23:11
81d9e49
Compare
Choose a tag to compare

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

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 calling generateRegistrationOptions()
    (#538)
  • [browser] The browserSupportsWebAuthnAutofill() helper will no longer break in environments
    in which PublicKeyCredential is not present
    (#557, with thanks to @clarafitzgerald)

Breaking Changes

  • [server] The following breaking changes were made in PR
    #529:
    • generateRegistrationOptions() now expects Base64URLString for excluded credential IDs
    • generateAuthenticationOptions() now expects Base64URLString for allowed credential IDs
    • credentialID returned from response verification methods is now a Base64URLString
    • AuthenticatorDevice.credentialID is now a Base64URLString
    • isoBase64URL.isBase64url() is now called isoBase64URL.isBase64URL()
  • [browser, server] The following breaking changes were made in PR
    #552:
    • generateRegistrationOptions() now accepts an optional Uint8Array instead of a string for
      userID
    • isoBase64URL.toString() and isoBase64URL.fromString() have been renamed
    • generateRegistrationOptions() will now generate random user IDs
    • user.id is now treated like a base64url string in startRegistration()
    • userHandle is now treated like a base64url string in startAuthentication()
  • [server] rpID is now a required argument when calling generateAuthenticationOptions()
    (#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

16 Feb 16:45
162f320
Compare
Choose a tag to compare

Packages

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

09 Feb 04:29
768f7d1
Compare
Choose a tag to compare

Packages

Changes

  • [server] Improved support for Next.js Edge runtime (#518, with thanks to @balazsorban44)

v9.0.1

26 Jan 06:15
ba7048c
Compare
Choose a tag to compare

Packages

Changes

  • [server] Fixed an issue with use with CBOR handling in runtime environments that restrict use of eval() (#511, with thanks to @Maronato)
  • [browser, types] Monorepo version sync

v9.0.0 - The one in which 11 characters were saved

21 Jan 06:10
8447417
Compare
Choose a tag to compare

Packages

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

20 Jan 06:56
bd8ad17
Compare
Choose a tag to compare

Packages

Changes

  • [browser] The WebAuthnError class can now be imported from @simplewebauthn/browser for simpler error detection and handling when calling startRegistration() and startAuthentication() (#505, with thanks to @zoontek)
  • [server] The COSEPublicKeyEC2, COSEPublicKeyOKP, and COSEPublicKeyRSA types can now be imported from @simplwebauthn/server/helpers to help type possible return values from decodeCredentialPublicKey() (#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 of generateAuthenticationOptions() (#507)