diff --git a/packages/connect-react/src/components/append/AppendAfterErrorScreen.tsx b/packages/connect-react/src/components/append/AppendAfterErrorScreen.tsx index 8d31d6fe..833c0ef8 100644 --- a/packages/connect-react/src/components/append/AppendAfterErrorScreen.tsx +++ b/packages/connect-react/src/components/append/AppendAfterErrorScreen.tsx @@ -63,7 +63,7 @@ const AppendAfterErrorScreen = ({ attestationOptions }: { attestationOptions: st void handleErrorSoft(situationCode, true, true, error); break; case AppendSituationCode.ClientExcludeCredentialsMatch: - void handleCredentialExistsError(error); + void handleCredentialExistsError(attestationOptions, error); break; case AppendSituationCode.ExplicitSkipByUser: void handleSkip(situationCode, true); diff --git a/packages/connect-react/src/components/append/AppendInitScreen.tsx b/packages/connect-react/src/components/append/AppendInitScreen.tsx index e4e03262..c4a8dc66 100644 --- a/packages/connect-react/src/components/append/AppendInitScreen.tsx +++ b/packages/connect-react/src/components/append/AppendInitScreen.tsx @@ -244,7 +244,7 @@ const AppendInitScreen = () => { setAppendLoading(false); break; case AppendSituationCode.ClientExcludeCredentialsMatch: - void handleCredentialExistsError(error); + void handleCredentialExistsError(attestationOptions, error); setAppendLoading(false); break; case AppendSituationCode.DeniedByPartialRollout: diff --git a/packages/connect-react/src/components/passkeyList/PasskeyListScreen.tsx b/packages/connect-react/src/components/passkeyList/PasskeyListScreen.tsx index 0a082d63..c0528ae6 100644 --- a/packages/connect-react/src/components/passkeyList/PasskeyListScreen.tsx +++ b/packages/connect-react/src/components/passkeyList/PasskeyListScreen.tsx @@ -137,7 +137,11 @@ const PasskeyListScreen = () => { } if (res.val.type === ConnectErrorType.ExcludeCredentialsMatch) { - return handleSituation(PasskeyListSituationCode.ClientExcludeCredentialsMatch, res.val); + return handleSituation( + PasskeyListSituationCode.ClientExcludeCredentialsMatch, + res.val, + startAppendRes.val.attestationOptions, + ); } return handleSituation(PasskeyListSituationCode.CboApiNotAvailablePostAuthenticator, res.val); @@ -171,7 +175,11 @@ const PasskeyListScreen = () => { statefulLoader.current.finish(); }; - const handleSituation = (situationCode: PasskeyListSituationCode, error?: ConnectError) => { + const handleSituation = ( + situationCode: PasskeyListSituationCode, + error?: ConnectError, + attestationOptions?: string, + ) => { const messageCode = `situation: ${situationCode}`; log.debug(messageCode); @@ -179,7 +187,10 @@ const PasskeyListScreen = () => { switch (situationCode) { case PasskeyListSituationCode.ClientExcludeCredentialsMatch: setAppendLoading(false); - void getConnectService().recordEventAppendCredentialExistsError(`${messageCode} ${error?.track()}`); + void getConnectService().recordEventAppendCredentialExistsError( + attestationOptions ?? '', + `${messageCode} ${error?.track()}`, + ); show(); break; case PasskeyListSituationCode.CboApiPasskeysNotSupportedLight: diff --git a/packages/connect-react/src/contexts/AppendProcessContext.ts b/packages/connect-react/src/contexts/AppendProcessContext.ts index 6513b5f3..7335e1ad 100644 --- a/packages/connect-react/src/contexts/AppendProcessContext.ts +++ b/packages/connect-react/src/contexts/AppendProcessContext.ts @@ -22,7 +22,7 @@ export interface AppendProcessContextProps { error?: ConnectError, ) => Promise; handleErrorHard: (situation: AppendSituationCode, expected: boolean, error?: ConnectError) => Promise; - handleCredentialExistsError: (error?: ConnectError) => Promise; + handleCredentialExistsError: (attestationOptions: string, error?: ConnectError) => Promise; handleSkip: (situation: AppendSituationCode, explicit?: boolean) => Promise; onReadMoreClick: () => Promise; flags: Flags | undefined; diff --git a/packages/connect-react/src/contexts/AppendProcessProvider.tsx b/packages/connect-react/src/contexts/AppendProcessProvider.tsx index 30cf0d34..e86dcb48 100644 --- a/packages/connect-react/src/contexts/AppendProcessProvider.tsx +++ b/packages/connect-react/src/contexts/AppendProcessProvider.tsx @@ -74,10 +74,10 @@ export const AppendProcessProvider: FC> = ({ children, }, [getConnectService, config]); const handleCredentialExistsError = useCallback( - async (error?: ConnectError) => { + async (attestationOptions: string, error?: ConnectError) => { log.debug('error (credential-exists)'); - await getConnectService().recordEventAppendCredentialExistsError(error?.track() ?? ''); + await getConnectService().recordEventAppendCredentialExistsError(error?.track() ?? '', attestationOptions); void config.onComplete('complete-noop', getConnectService().encodeClientState()); }, [getConnectService, config], diff --git a/packages/web-core/src/services/ConnectService.ts b/packages/web-core/src/services/ConnectService.ts index 1e9558f4..475369f8 100644 --- a/packages/web-core/src/services/ConnectService.ts +++ b/packages/web-core/src/services/ConnectService.ts @@ -644,8 +644,13 @@ export class ConnectService { return this.#recordEvent(PasskeyEventType.UserAppendAfterLoginErrorBlacklisted); } - recordEventAppendCredentialExistsError(messageCode: string) { - return this.#recordEvent(PasskeyEventType.AppendCredentialExists, messageCode); + recordEventAppendCredentialExistsError(messageCode: string, attestationOptions: string) { + let challenge; + if (attestationOptions) { + challenge = WebAuthnService.challengeFromAttestationOptions(attestationOptions); + } + + return this.#recordEvent(PasskeyEventType.AppendCredentialExists, messageCode, challenge); } recordEventAppendError() {