diff --git a/packages/javascript-sdk/src/fr-webauthn/fr-webauthn.test.ts b/packages/javascript-sdk/src/fr-webauthn/fr-webauthn.test.ts index bfb73d20..15bce073 100644 --- a/packages/javascript-sdk/src/fr-webauthn/fr-webauthn.test.ts +++ b/packages/javascript-sdk/src/fr-webauthn/fr-webauthn.test.ts @@ -210,4 +210,38 @@ describe('Test FRWebAuthn class with Conditional UI', () => { }), ); }); + + it('should throw NotSupportedError if WebAuthn is not supported', async () => { + // Mock WebAuthn not supported + const spy = vi.spyOn(FRWebAuthn, 'isWebAuthnSupported').mockReturnValue(false); + + await expect(FRWebAuthn.getRegistrationCredential({} as any)).rejects.toThrow( + 'PublicKeyCredential not supported by this browser', + ); + + spy.mockRestore(); + }); + + it('should correctly convert _allowCredentials id to Int8Array', () => { + const metadata: any = { + _action: 'webauthn_authentication', + challenge: 'JEisuqkVMhI490jM0/iEgrRz+j94OoGc7gdY4gYicSk=', + relyingPartyId: '', + _allowCredentials: [ + { + type: 'public-key', + id: [1, 2, 3, 4], + transports: ['usb'], + }, + ], + timeout: 60000, + }; + + const publicKey = FRWebAuthn.createAuthenticationPublicKey(metadata); + + expect(publicKey.allowCredentials).toBeDefined(); + expect(publicKey.allowCredentials![0].id).toBeInstanceOf(Int8Array); + const idArray = publicKey.allowCredentials![0].id as Int8Array; + expect(Array.from(idArray)).toEqual([1, 2, 3, 4]); + }); }); diff --git a/packages/javascript-sdk/src/fr-webauthn/index.ts b/packages/javascript-sdk/src/fr-webauthn/index.ts index d07a3072..ee1ec5ec 100644 --- a/packages/javascript-sdk/src/fr-webauthn/index.ts +++ b/packages/javascript-sdk/src/fr-webauthn/index.ts @@ -469,7 +469,7 @@ abstract class FRWebAuthn { options: PublicKeyCredentialCreationOptions, ): Promise { // Feature check before we attempt registering a device - if (this.isWebAuthnSupported()) { + if (!this.isWebAuthnSupported()) { const e = new Error('PublicKeyCredential not supported by this browser'); e.name = WebAuthnOutcomeType.NotSupportedError; throw e; @@ -534,7 +534,14 @@ abstract class FRWebAuthn { // Use the structured _allowCredentials if available, otherwise parse the string format let allowCredentialsValue: PublicKeyCredentialDescriptor[] | undefined; if (_allowCredentials && Array.isArray(_allowCredentials)) { - allowCredentialsValue = _allowCredentials; + // The incoming _allowCredentials entries have an `id` property of type `Array`, which is rejected by `navigator.credentials.get()`. + // Converting it to a TypedArray here to meet the spec (https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredentialRequestOptions#id). + allowCredentialsValue = _allowCredentials.map((cred) => { + return { + ...cred, + id: new Int8Array(cred.id as unknown as number[]), + }; + }); } else { allowCredentialsValue = parseCredentials(allowCredentials || acceptableCredentials || ''); }