diff --git a/docs/authentication.md b/docs/authentication.md index 880e704..8c86a39 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -74,8 +74,7 @@ The following options are available. | `domain` | `window.location.hostname` | By default, the current domain name is used. Also known as "relying party id". You may want to customize it for ... | `allowedCredentials` | The list of credentials and the transports it supports. Used to skip passkey selection. Either a list of credential ids (discouraged) or list of credential objects with `id` and supported `transports` (recommended). | `autocomplete` | `false` | See concepts - - +| `customProperties` | `{}` | An object of additional properties that will be merged into the WebAuthn authenticate options. This can be used to explicitly set fields such as `extensions`. 3️⃣ Send the payload to the server diff --git a/docs/registration.md b/docs/registration.md index ee3dd04..7af0b28 100644 --- a/docs/registration.md +++ b/docs/registration.md @@ -64,7 +64,7 @@ Besides the required `user` and `challenge`, it has following options. | `timeout` | - | How long the native authentication popup stays open before aborting the authentication process. | `attestation` | `true` | Whether or not to provide "attestation" in the result. The attestation can be used to prove the authenticator device model's authenticity. Note that not all authenticators provide this (looking at you apple), it might be anonymized, and its verification is complex. | `domain` | `window.location.hostname` | This can be set to a parent domain, to have the passkey valid for all subdomains. - +| `customProperties` | `{}` | An object of additional properties that will be merged into the WebAuthn create options. This can be used to explicitly set fields such as `excludeCredentials`. diff --git a/package-lock.json b/package-lock.json index 3b5e694..d62b496 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@passwordless-id/webauthn", - "version": "2.0.0", + "version": "2.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@passwordless-id/webauthn", - "version": "2.0.0", + "version": "2.1.2", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.12", @@ -16,6 +16,9 @@ "jest-ts-webcompat-resolver": "^1.0.0", "ts-jest": "^29.1.3", "typescript": "^5.4.5" + }, + "funding": { + "url": "https://github.com/sponsors/passwordless-id" } }, "node_modules/@ampproject/remapping": { diff --git a/src/client.ts b/src/client.ts index d3d8f67..8308da1 100644 --- a/src/client.ts +++ b/src/client.ts @@ -53,6 +53,20 @@ let ongoingAuth: AbortController | null = null; * @param {'discouraged'|'preferred'|'required'} [discoverable] A "discoverable" credential can be selected using `authenticate(...)` without providing credential IDs. * Instead, a native pop-up will appear for user selection. * This may have an impact on the "passkeys" user experience and syncing behavior of the key. + * @param {Record} [options.customProperties] - **Advanced usage**: An object of additional + * properties that will be merged into the WebAuthn create options. This can be used to + * explicitly set fields such as `excludeCredentials`. + * + * @example + * const registration = await register({ + * user: { id: 'user-id', name: 'john', displayName: 'John' }, + * challenge: 'base64url-encoded-challenge', + * customProperties: { + * excludeCredentials: [ + * { id: 'base64url-credential-id', type: 'public-key' }, + * ], + * }, + * }); */ export async function register(options: RegisterOptions): Promise { @@ -92,7 +106,8 @@ export async function register(options: RegisterOptions): Promise} [options.customProperties] - **Advanced usage**: An object of additional + * properties that will be merged into the WebAuthn authenticate options. This can be used to + * explicitly set fields such as `extensions`. + * + * @example + * const authentication = await authenticate({ + * challenge: 'base64url-encoded-challenge', + * allowCredentials: [], + * customProperties: { + * extensions: { + * uvm: true, // User verification methods extension + * appid: "https://legacy-app-id.example.com", // App ID extension for backward compatibility + * }, + * }, + * }); */ export async function authenticate(options: AuthenticateOptions): Promise { if (!utils.isBase64url(options.challenge)) @@ -165,6 +195,7 @@ export async function authenticate(options: AuthenticateOptions): Promise; } - export interface User { - id?: string - name: string - displayName?: string + id?: string; + name: string; + displayName?: string; } /** * @see PublicKeyCredentialDescriptor */ export interface CredentialDescriptor { - id: Base64URLString, - transports: ExtendedAuthenticatorTransport[] + id: Base64URLString; + transports: ExtendedAuthenticatorTransport[]; } export interface AuthenticateOptions extends CommonOptions { - allowCredentials?: (CredentialDescriptor | string)[] - autocomplete?: boolean + allowCredentials?: (CredentialDescriptor | string)[]; + autocomplete?: boolean; + customProperties?: Record; } - - /********************************** JSON PAYLOADS **********************/ export interface RegistrationJSON extends RegistrationResponseJSON { - user: User // Added by this library, not by the WebAuthn protocol + user: User; // Added by this library, not by the WebAuthn protocol } export type AuthenticationJSON = AuthenticationResponseJSON; @@ -82,7 +79,6 @@ export interface RegistrationResponseJSON { type: PublicKeyCredentialType; } - /** * A slightly-modified AuthenticatorAttestationResponse to simplify working with ArrayBuffers that * are Base64URL-encoded in the browser so that they can be sent as JSON to the server. @@ -113,7 +109,6 @@ export interface AuthenticationResponseJSON { type: PublicKeyCredentialType; } - /** * A slightly-modified AuthenticatorAssertionResponse to simplify working with ArrayBuffers that * are Base64URL-encoded in the browser so that they can be sent as JSON to the server. @@ -130,11 +125,10 @@ export interface AuthenticatorAssertionResponseJSON { /** * WebAuthn added transports that are not yet defined in the DOM definitions. * However, it's partly obsoleted by the `hints` in the registration/authentication request. - * + * * https://w3c.github.io/webauthn/#enumdef-authenticatortransport */ -export type ExtendedAuthenticatorTransport = AuthenticatorTransport | 'smart-card'; // missing in the current DOM types - +export type ExtendedAuthenticatorTransport = AuthenticatorTransport | "smart-card"; // missing in the current DOM types /************************** PARSED **************************/ @@ -142,26 +136,26 @@ export type ExtendedAuthenticatorTransport = AuthenticatorTransport | 'smart-car * https://w3c.github.io/webauthn/#dictionary-client-data */ export interface CollectedClientData { - type: string - challenge: Base64URLString - origin: string - topOrigin?: string + type: string; + challenge: Base64URLString; + origin: string; + topOrigin?: string; crossOrigin?: boolean; } export interface AuthenticatorParsed { - rpIdHash:Base64URLString, + rpIdHash: Base64URLString; flags: { - userPresent: boolean, - userVerified: boolean, - backupEligibility: boolean, - backupState: boolean, - attestedData: boolean, - extensionsIncluded: boolean - }, - signCount: number, - aaguid: string, - attestation?: Base64URLString + userPresent: boolean; + userVerified: boolean; + backupEligibility: boolean; + backupState: boolean; + attestedData: boolean; + extensionsIncluded: boolean; + }; + signCount: number; + aaguid: string; + attestation?: Base64URLString; } /** @@ -171,41 +165,38 @@ export interface AuthenticatorParsed { /************************** RESULTS *************************/ export interface RegistrationInfo { - user: UserInfo - credential: CredentialInfo - authenticator: AuthenticatorInfo - synced: boolean - userVerified: boolean + user: UserInfo; + credential: CredentialInfo; + authenticator: AuthenticatorInfo; + synced: boolean; + userVerified: boolean; } - export interface AuthenticationInfo { - credentialId: Base64URLString - userId?: Base64URLString - userVerified: boolean - counter: number - authenticatorAttachment?: AuthenticatorAttachment + credentialId: Base64URLString; + userId?: Base64URLString; + userVerified: boolean; + counter: number; + authenticatorAttachment?: AuthenticatorAttachment; } - export interface UserInfo { - id: string - name: string - displayName: string + id: string; + name: string; + displayName: string; } - export interface CredentialInfo { - id: string - publicKey: string - algorithm: NamedAlgo - transports: ExtendedAuthenticatorTransport[] + id: string; + publicKey: string; + algorithm: NamedAlgo; + transports: ExtendedAuthenticatorTransport[]; } export interface AuthenticatorInfo { - aaguid: string - name: string - icon_light: string - icon_dark: string - counter: number + aaguid: string; + name: string; + icon_light: string; + icon_dark: string; + counter: number; }