diff --git a/app/javascript/packages/webauthn/enroll-webauthn-device.spec.ts b/app/javascript/packages/webauthn/enroll-webauthn-device.spec.ts index be434df81d8..2e0baaf57d2 100644 --- a/app/javascript/packages/webauthn/enroll-webauthn-device.spec.ts +++ b/app/javascript/packages/webauthn/enroll-webauthn-device.spec.ts @@ -62,6 +62,7 @@ describe('enrollWebauthnDevice', () => { challenge, excludeCredentials, authenticatorAttachment: 'cross-platform', + hints: ['security-key'], }); expect(navigator.credentials.create).to.have.been.calledWith({ @@ -85,8 +86,9 @@ describe('enrollWebauthnDevice', () => { timeout: 800000, attestation: 'none', authenticatorSelection: { - authenticatorAttachment: 'cross-platform', userVerification: 'discouraged', + authenticatorAttachment: 'cross-platform', + hints: ['security-key'], }, excludeCredentials: [ { @@ -132,12 +134,14 @@ describe('enrollWebauthnDevice', () => { challenge, excludeCredentials, authenticatorAttachment: 'platform', + hints: ['client-device'], }); expect(navigator.credentials.create).to.have.been.calledWithMatch({ publicKey: { authenticatorSelection: { authenticatorAttachment: 'platform', + hints: ['client-device'], }, }, }); diff --git a/app/javascript/packages/webauthn/enroll-webauthn-device.ts b/app/javascript/packages/webauthn/enroll-webauthn-device.ts index ffbae3a19cf..2dae75c71d3 100644 --- a/app/javascript/packages/webauthn/enroll-webauthn-device.ts +++ b/app/javascript/packages/webauthn/enroll-webauthn-device.ts @@ -15,6 +15,8 @@ interface AuthenticatorAttestationResponseBrowserSupport getAuthenticatorData: AuthenticatorAttestationResponse['getAuthenticatorData'] | undefined; } +type PublicKeyCredentialHintType = 'client-device' | 'security-key' | 'hybrid'; + interface EnrollOptions { user: PublicKeyCredentialUserEntity; @@ -23,6 +25,8 @@ interface EnrollOptions { excludeCredentials: PublicKeyCredentialDescriptor[]; authenticatorAttachment?: AuthenticatorAttachment; + + hints?: Array; } interface EnrollResult { @@ -37,6 +41,10 @@ interface EnrollResult { transports?: string[]; } +interface AuthenticatorSelectionCriteriaWithHints extends AuthenticatorSelectionCriteria { + hints?: Array; +} + /** * All possible algorithms supported within the CBOR Object Signing and Encryption (COSE) format. * @@ -76,6 +84,7 @@ async function enrollWebauthnDevice({ challenge, excludeCredentials, authenticatorAttachment, + hints, }: EnrollOptions): Promise { const credential = (await navigator.credentials.create({ publicKey: { @@ -89,7 +98,8 @@ async function enrollWebauthnDevice({ // Prevents user from needing to use PIN with Security Key userVerification: 'discouraged', authenticatorAttachment, - }, + hints, + } as AuthenticatorSelectionCriteriaWithHints, excludeCredentials, }, })) as PublicKeyCredential; diff --git a/app/javascript/packs/webauthn-setup.ts b/app/javascript/packs/webauthn-setup.ts index 614335d8d23..743b99c827c 100644 --- a/app/javascript/packs/webauthn-setup.ts +++ b/app/javascript/packs/webauthn-setup.ts @@ -56,6 +56,7 @@ function webauthn() { .filter(Boolean), ), authenticatorAttachment: platformAuthenticator ? 'platform' : 'cross-platform', + hints: platformAuthenticator ? ['client-device', 'hybrid'] : ['security-key'], }) .then((result) => { (document.getElementById('webauthn_id') as HTMLInputElement).value = result.webauthnId;