From ca9dfd78e6770fcfd0b299228c971dc70de7453a Mon Sep 17 00:00:00 2001 From: Taesu <166604494+bytaesu@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:41:11 +0900 Subject: [PATCH] fix(one-tap): respect user dismiss actions in prompt retry logic (#7211) --- .../better-auth/src/plugins/one-tap/client.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/better-auth/src/plugins/one-tap/client.ts b/packages/better-auth/src/plugins/one-tap/client.ts index 39a28591d9..f0dd5bf10c 100644 --- a/packages/better-auth/src/plugins/one-tap/client.ts +++ b/packages/better-auth/src/plugins/one-tap/client.ts @@ -105,6 +105,15 @@ function isFedCMSupported() { return typeof window !== "undefined" && "IdentityCredential" in window; } +/** + * Reasons that should NOT trigger a retry. + * @see https://developers.google.com/identity/gsi/web/reference/js-reference + */ +const noRetryReasons = { + dismissed: ["credential_returned", "cancel_called"], + skipped: ["user_cancel", "tap_outside"], +} as const; + export const oneTapClient = (options: GoogleOneTapOptions) => { return { id: "one-tap", @@ -241,6 +250,11 @@ export const oneTapClient = (options: GoogleOneTapOptions) => { notification.isDismissedMoment && notification.isDismissedMoment() ) { + const reason = notification.getDismissedReason?.(); + if (noRetryReasons.dismissed.includes(reason)) { + opts?.onPromptNotification?.(notification); + return; + } if (attempt < maxAttempts) { const delay = Math.pow(2, attempt) * baseDelay; setTimeout(() => handlePrompt(attempt + 1), delay); @@ -251,6 +265,11 @@ export const oneTapClient = (options: GoogleOneTapOptions) => { notification.isSkippedMoment && notification.isSkippedMoment() ) { + const reason = notification.getSkippedReason?.(); + if (noRetryReasons.skipped.includes(reason)) { + opts?.onPromptNotification?.(notification); + return; + } if (attempt < maxAttempts) { const delay = Math.pow(2, attempt) * baseDelay; setTimeout(() => handlePrompt(attempt + 1), delay);