diff --git a/packages/browser/src/helpers/toPublicKeyCredentialDescriptor.ts b/packages/browser/src/helpers/toPublicKeyCredentialDescriptor.ts index 8fad78b7..127713a9 100644 --- a/packages/browser/src/helpers/toPublicKeyCredentialDescriptor.ts +++ b/packages/browser/src/helpers/toPublicKeyCredentialDescriptor.ts @@ -10,5 +10,11 @@ export default function toPublicKeyCredentialDescriptor( return { ...descriptor, id: base64URLStringToBuffer(id), + /** + * `descriptor.transports` is an array of our `AuthenticatorTransport` that includes newer + * transports that TypeScript's DOM lib is ignorant of. Convince TS that our list of transports + * are fine to pass to WebAuthn since browsers will recognize the new value. + */ + transports: descriptor.transports as AuthenticatorTransport[], }; } diff --git a/packages/browser/src/methods/startAuthentication.test.ts b/packages/browser/src/methods/startAuthentication.test.ts index 725cd4e6..658b67c9 100644 --- a/packages/browser/src/methods/startAuthentication.test.ts +++ b/packages/browser/src/methods/startAuthentication.test.ts @@ -202,6 +202,23 @@ test('should include extension results when no extensions specified', async () = expect(response.clientExtensionResults).toEqual({}); }); +test('should support "cable" transport', async () => { + const opts: PublicKeyCredentialRequestOptionsJSON = { + ...goodOpts1, + allowCredentials: [ + { + ...goodOpts1.allowCredentials![0], + transports: ["cable"], + }, + ] + }; + + await startAuthentication(opts); + + expect(mockNavigatorGet.mock.calls[0][0].publicKey.allowCredentials[0].transports[0]) + .toEqual("cable"); +}); + describe('WebAuthnError', () => { describe('AbortError', () => { const AbortError = generateCustomError('AbortError'); diff --git a/packages/browser/src/methods/startRegistration.test.ts b/packages/browser/src/methods/startRegistration.test.ts index 360884e9..fcd4a2cb 100644 --- a/packages/browser/src/methods/startRegistration.test.ts +++ b/packages/browser/src/methods/startRegistration.test.ts @@ -176,6 +176,41 @@ test('should include extension results when no extensions specified', async () = expect(response.clientExtensionResults).toEqual({}); }); +test('should support "cable" transport in excludeCredentials', async () => { + const opts: PublicKeyCredentialCreationOptionsJSON = { + ...goodOpts1, + excludeCredentials: [ + { + ...goodOpts1.excludeCredentials![0], + transports: ["cable"], + }, + ] + }; + + await startRegistration(opts); + + expect(mockNavigatorCreate.mock.calls[0][0].publicKey.excludeCredentials[0].transports[0]) + .toEqual("cable"); +}); + +test('should return "cable" transport from response', async () => { + mockNavigatorCreate.mockResolvedValue({ + id: 'foobar', + rawId: utf8StringToBuffer('foobar'), + response: { + attestationObject: Buffer.from(mockAttestationObject, 'ascii'), + clientDataJSON: Buffer.from(mockClientDataJSON, 'ascii'), + getTransports: () => (["cable"]), + }, + getClientExtensionResults: () => ({}), + type: 'webauthn.create', + }); + + const response = await startRegistration(goodOpts1); + + expect(response.transports).toEqual(["cable"]); +}); + describe('WebAuthnError', () => { describe('AbortError', () => { const AbortError = generateCustomError('AbortError'); diff --git a/packages/typescript-types/extract-dom-types.ts b/packages/typescript-types/extract-dom-types.ts index 856cb633..75d16ccc 100644 --- a/packages/typescript-types/extract-dom-types.ts +++ b/packages/typescript-types/extract-dom-types.ts @@ -20,7 +20,6 @@ const types = [ 'AuthenticatorAssertionResponse', 'AttestationConveyancePreference', 'AuthenticatorAttestationResponse', - 'AuthenticatorTransport', 'AuthenticationExtensionsClientInputs', 'AuthenticationExtensionsClientOutputs', 'AuthenticatorSelectionCriteria', diff --git a/packages/typescript-types/src/index.ts b/packages/typescript-types/src/index.ts index a9308616..751474a5 100644 --- a/packages/typescript-types/src/index.ts +++ b/packages/typescript-types/src/index.ts @@ -6,7 +6,6 @@ import type { AuthenticatorAssertionResponse, AuthenticatorAttestationResponse, - AuthenticatorTransport, COSEAlgorithmIdentifier, PublicKeyCredential, PublicKeyCredentialCreationOptions, @@ -43,8 +42,9 @@ export interface PublicKeyCredentialRequestOptionsJSON } export interface PublicKeyCredentialDescriptorJSON - extends Omit { + extends Omit { id: Base64URLString; + transports?: AuthenticatorTransport[]; } export interface PublicKeyCredentialUserEntityJSON @@ -146,3 +146,9 @@ export interface AuthenticatorAttestationResponseFuture extends AuthenticatorAtt getPublicKey?: () => ArrayBuffer; getPublicKeyAlgorithm?: () => COSEAlgorithmIdentifier[]; } + +/** + * Communication methods by which an authenticator can talk with the browser to perform WebAuthn + * registration and authentication. + */ +export type AuthenticatorTransport = "ble" | "internal" | "nfc" | "usb" | "cable";