From 8c8ffa939708781ef5e0212aaffdaa29ee9f3bf5 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 14 Jun 2024 13:42:30 +0530 Subject: [PATCH] Add a hint to retry on other devices --- .../accounts/src/pages/passkeys/verify.tsx | 27 ++++++++++++++++--- .../next/locales/en-US/translation.json | 1 + 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/web/apps/accounts/src/pages/passkeys/verify.tsx b/web/apps/accounts/src/pages/passkeys/verify.tsx index 2c30c22641..5c909e76f4 100644 --- a/web/apps/accounts/src/pages/passkeys/verify.tsx +++ b/web/apps/accounts/src/pages/passkeys/verify.tsx @@ -32,7 +32,8 @@ const Page = () => { | "webAuthnNotSupported" /* Unrecoverable error */ | "unknownRedirect" /* Unrecoverable error */ | "unrecoverableFailure" /* Unrecoverable error - generic */ - | "failed" /* Recoverable error */ + | "failedDuringSignChallenge" /* Recoverable error in signChallenge */ + | "failed" /* Recoverable error otherwise */ | "needUserFocus" /* See docs for `Continuation` */ | "waitingForUser" /* ...to authenticate with their passkey */ | "redirectingWeb" /* Redirect back to the requesting app (HTTP) */ @@ -143,7 +144,7 @@ const Page = () => { try { credential = await signChallenge(options.publicKey); if (!credential) { - setStatus("failed"); + setStatus("failedDuringSignChallenge"); return; } } catch (e) { @@ -155,7 +156,7 @@ const Page = () => { ) { setStatus("needUserFocus"); } else { - setStatus("failed"); + setStatus("failedDuringSignChallenge"); } return; } @@ -231,6 +232,13 @@ const Page = () => { unknownRedirect: , webAuthnNotSupported: , unrecoverableFailure: , + failedDuringSignChallenge: ( + + ), failed: ( ), @@ -345,6 +353,14 @@ const Verify: React.FC = ({ onVerify }) => { }; interface RetriableFailedProps { + /** + * Set this attribute to indicate that this failure occurred during the + * actual passkey verification (`navigator.credentials.get`). + * + * We customize the error message for such cases to give a hint to the user + * that they can try on their other devices too. + */ + duringSignChallenge?: boolean; /** Callback invoked when the user presses the try again button. */ onRetry: () => void; /** @@ -358,6 +374,7 @@ interface RetriableFailedProps { } const RetriableFailed: React.FC = ({ + duringSignChallenge, onRetry, onRecover, }) => { @@ -366,7 +383,9 @@ const RetriableFailed: React.FC = ({ {t("passkey_login_failed")} - {t("passkey_login_generic_error")} + {duringSignChallenge + ? t("passkey_login_credential_hint") + : t("passkey_login_generic_error")}