UNPKG

better-auth

Version:

The most comprehensive authentication framework for TypeScript.

1 lines 20 kB
{"version":3,"file":"client.mjs","names":["isRequestInProgress: AbortController | null","callback","contextValue","context","autoSelect","cancelOnTapOutside","error: any"],"sources":["../../../src/plugins/one-tap/client.ts"],"sourcesContent":["/// <reference types=\"@types/google.accounts\" />\nimport type {\n\tBetterAuthClientPlugin,\n\tClientFetchOption,\n} from \"@better-auth/core\";\n\ndeclare global {\n\tinterface Window {\n\t\tgoogleScriptInitialized?: boolean | undefined;\n\t}\n}\n\nexport interface GsiButtonConfiguration {\n\t/**\n\t * The button type: icon, or standard button.\n\t */\n\ttype: \"standard\" | \"icon\";\n\n\t/**\n\t * The button theme. For example, filled_blue or filled_black.\n\t * outline A standard button theme:\n\t * filled_blue A blue-filled button theme:\n\t * filled_black A black-filled button theme:\n\t */\n\ttheme?: \"outline\" | \"filled_blue\" | \"filled_black\";\n\n\t/**\n\t * The button size. For example, small or large.\n\t */\n\tsize?: \"small\" | \"medium\" | \"large\";\n\n\t/**\n\t * The button text. The default value is signin_with.\n\t * There are no visual differences for the text of icon buttons that\n\t * have different text attributes. The only exception is when the\n\t * text is read for screen accessibility.\n\t *\n\t * signin_with The button text is “Sign in with Google”:\n\t * signup_with The button text is “Sign up with Google”:\n\t * continue_with The button text is “Continue with Google”:\n\t * signup_with The button text is “Sign in”:\n\t */\n\ttext?: \"signin_with\" | \"signup_with\" | \"continue_with\" | \"signin\";\n\n\t/**\n\t * The button shape. The default value is rectangular.\n\t */\n\tshape?: \"rectangular\" | \"pill\" | \"circle\" | \"square\";\n\n\t/**\n\t * The alignment of the Google logo. The default value is left.\n\t * This attribute only applies to the standard button type.\n\t */\n\tlogo_alignment?: \"left\" | \"center\";\n\n\t/**\n\t * The minimum button width, in pixels. The maximum width is 400\n\t * pixels.\n\t */\n\twidth?: number;\n\n\t/**\n\t * The pre-set locale of the button text. If it's not set, the\n\t * browser's default locale or the Google session user’s preference\n\t * is used.\n\t */\n\tlocale?: string;\n\n\t/**\n\t * You can define a JavaScript function to be called when the\n\t * Sign in with Google button is clicked.\n\t */\n\tclick_listener?: () => void;\n\n\t/**\n\t * Optional, as multiple Sign in with Google buttons can be\n\t * rendered on the same page, you can assign each button with a\n\t * unique string. The same string would return along with the ID\n\t * token, so you can identify which button user clicked to sign in.\n\t */\n\tstate?: string;\n}\n\nexport interface GoogleOneTapOptions {\n\t/**\n\t * Google client ID\n\t */\n\tclientId: string;\n\t/**\n\t * Auto select the account if the user is already signed in\n\t */\n\tautoSelect?: boolean | undefined;\n\t/**\n\t * Cancel the flow when the user taps outside the prompt\n\t *\n\t * Note: To use this option, disable `promptOptions.fedCM`\n\t */\n\tcancelOnTapOutside?: boolean | undefined;\n\t/**\n\t * The mode to use for the Google One Tap flow\n\t *\n\t * popup: Use a popup window\n\t * redirect: Redirect the user to the Google One Tap flow\n\t *\n\t * @default \"popup\"\n\t */\n\tuxMode?: (\"popup\" | \"redirect\") | undefined;\n\t/**\n\t * The context to use for the Google One Tap flow.\n\t *\n\t * @see {@link https://developers.google.com/identity/gsi/web/reference/js-reference}\n\t * @default \"signin\"\n\t */\n\tcontext?: (\"signin\" | \"signup\" | \"use\") | undefined;\n\t/**\n\t * Additional configuration options to pass to the Google One Tap API.\n\t */\n\tadditionalOptions?: Record<string, any> | undefined;\n\t/**\n\t * Configuration options for the prompt and exponential backoff behavior.\n\t */\n\tpromptOptions?:\n\t\t| {\n\t\t\t\t/**\n\t\t\t\t * Base delay (in milliseconds) for exponential backoff.\n\t\t\t\t * @default 1000\n\t\t\t\t */\n\t\t\t\tbaseDelay?: number;\n\t\t\t\t/**\n\t\t\t\t * Maximum number of prompt attempts before calling onPromptNotification.\n\t\t\t\t * @default 5\n\t\t\t\t */\n\t\t\t\tmaxAttempts?: number;\n\t\t\t\t/**\n\t\t\t\t * Whether to support FedCM (Federated Credential Management) support.\n\t\t\t\t *\n\t\t\t\t * @see {@link https://developer.chrome.com/docs/identity/fedcm/overview}\n\t\t\t\t * @default true\n\t\t\t\t */\n\t\t\t\tfedCM?: boolean | undefined;\n\t\t }\n\t\t| undefined;\n}\n\nexport interface GoogleOneTapActionOptions\n\textends Omit<GoogleOneTapOptions, \"clientId\" | \"promptOptions\"> {\n\tfetchOptions?: ClientFetchOption | undefined;\n\t/**\n\t * Callback URL.\n\t */\n\tcallbackURL?: string | undefined;\n\t/**\n\t * Optional callback that receives the prompt notification if (or when) the prompt is dismissed or skipped.\n\t * This lets you render an alternative UI (e.g. a Google Sign-In button) to restart the process.\n\t */\n\tonPromptNotification?: ((notification?: any | undefined) => void) | undefined;\n\tnonce?: string | undefined;\n\t/**\n\t * Button mode configuration. When provided, renders a \"Sign In with Google\" button\n\t * instead of showing the One Tap prompt.\n\t */\n\tbutton?:\n\t\t| {\n\t\t\t\t/**\n\t\t\t\t * The HTML element or CSS selector where the button should be rendered.\n\t\t\t\t * If a string is provided, it will be used as a CSS selector.\n\t\t\t\t */\n\t\t\t\tcontainer: HTMLElement | string;\n\t\t\t\t/**\n\t\t\t\t * Button configuration options\n\t\t\t\t */\n\t\t\t\tconfig?: GsiButtonConfiguration | undefined;\n\t\t }\n\t\t| undefined;\n}\n\ninterface IdentityCredential {\n\treadonly configURL: string;\n\treadonly isAutoSelected: boolean;\n\ttoken: string;\n}\n\nlet isRequestInProgress: AbortController | null = null;\n\nfunction isFedCMSupported() {\n\treturn typeof window !== \"undefined\" && \"IdentityCredential\" in window;\n}\n\n/**\n * Reasons that should NOT trigger a retry.\n * @see https://developers.google.com/identity/gsi/web/reference/js-reference\n */\nconst noRetryReasons = {\n\tdismissed: [\"credential_returned\", \"cancel_called\"],\n\tskipped: [\"user_cancel\", \"tap_outside\"],\n} as const;\n\nexport const oneTapClient = (options: GoogleOneTapOptions) => {\n\treturn {\n\t\tid: \"one-tap\",\n\t\tfetchPlugins: [\n\t\t\t{\n\t\t\t\tid: \"fedcm-signout-handle\",\n\t\t\t\tname: \"FedCM Sign-Out Handler\",\n\t\t\t\thooks: {\n\t\t\t\t\tasync onResponse(ctx) {\n\t\t\t\t\t\tif (!ctx.request.url.toString().includes(\"/sign-out\")) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (options.promptOptions?.fedCM === false || !isFedCMSupported()) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnavigator.credentials.preventSilentAccess();\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\tgetActions: ($fetch, _) => {\n\t\t\treturn {\n\t\t\t\toneTap: async (\n\t\t\t\t\topts?: GoogleOneTapActionOptions | undefined,\n\t\t\t\t\tfetchOptions?: ClientFetchOption | undefined,\n\t\t\t\t) => {\n\t\t\t\t\tif (isRequestInProgress && !isRequestInProgress.signal.aborted) {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\"A Google One Tap request is already in progress. Please wait.\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeof window === \"undefined\" || !window.document) {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\"Google One Tap is only available in browser environments\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Button mode: render a button instead of showing the prompt\n\t\t\t\t\tif (opts?.button) {\n\t\t\t\t\t\tawait loadGoogleScript();\n\n\t\t\t\t\t\tconst container =\n\t\t\t\t\t\t\ttypeof opts.button.container === \"string\"\n\t\t\t\t\t\t\t\t? document.querySelector<HTMLElement>(opts.button.container)\n\t\t\t\t\t\t\t\t: opts.button.container;\n\n\t\t\t\t\t\tif (!container) {\n\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\"Google One Tap: Button container not found\",\n\t\t\t\t\t\t\t\topts.button.container,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tasync function callback(idToken: string) {\n\t\t\t\t\t\t\tawait $fetch(\"/one-tap/callback\", {\n\t\t\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\t\t\tbody: { idToken },\n\t\t\t\t\t\t\t\t...opts?.fetchOptions,\n\t\t\t\t\t\t\t\t...fetchOptions,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif ((!opts?.fetchOptions && !fetchOptions) || opts?.callbackURL) {\n\t\t\t\t\t\t\t\twindow.location.href = opts?.callbackURL ?? \"/\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst { autoSelect, cancelOnTapOutside, context } = opts ?? {};\n\t\t\t\t\t\tconst contextValue = context ?? options.context ?? \"signin\";\n\n\t\t\t\t\t\twindow.google?.accounts.id.initialize({\n\t\t\t\t\t\t\tclient_id: options.clientId,\n\t\t\t\t\t\t\tcallback: async (response: { credential: string }) => {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tawait callback(response.credential);\n\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\tconsole.error(\"Error during button callback:\", error);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tauto_select: autoSelect,\n\t\t\t\t\t\t\tcancel_on_tap_outside: cancelOnTapOutside,\n\t\t\t\t\t\t\tcontext: contextValue,\n\t\t\t\t\t\t\tux_mode: opts?.uxMode || \"popup\",\n\t\t\t\t\t\t\tnonce: opts?.nonce,\n\t\t\t\t\t\t\titp_support: true,\n\t\t\t\t\t\t\t...options.additionalOptions,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\twindow.google?.accounts.id.renderButton(\n\t\t\t\t\t\t\tcontainer,\n\t\t\t\t\t\t\topts.button.config ?? {\n\t\t\t\t\t\t\t\ttype: \"icon\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tasync function callback(idToken: string) {\n\t\t\t\t\t\tawait $fetch(\"/one-tap/callback\", {\n\t\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\t\tbody: { idToken },\n\t\t\t\t\t\t\t...opts?.fetchOptions,\n\t\t\t\t\t\t\t...fetchOptions,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif ((!opts?.fetchOptions && !fetchOptions) || opts?.callbackURL) {\n\t\t\t\t\t\t\twindow.location.href = opts?.callbackURL ?? \"/\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst { autoSelect, cancelOnTapOutside, context } = opts ?? {};\n\t\t\t\t\tconst contextValue = context ?? options.context ?? \"signin\";\n\t\t\t\t\tconst clients = {\n\t\t\t\t\t\tfedCM: async () => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst identityCredential = (await navigator.credentials.get({\n\t\t\t\t\t\t\t\t\tidentity: {\n\t\t\t\t\t\t\t\t\t\tcontext: contextValue,\n\t\t\t\t\t\t\t\t\t\tproviders: [\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tconfigURL: \"https://accounts.google.com/gsi/fedcm.json\",\n\t\t\t\t\t\t\t\t\t\t\t\tclientId: options.clientId,\n\t\t\t\t\t\t\t\t\t\t\t\tnonce: opts?.nonce,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tmediation: autoSelect ? \"optional\" : \"required\",\n\t\t\t\t\t\t\t\t\tsignal: isRequestInProgress?.signal,\n\t\t\t\t\t\t\t\t} as any)) as IdentityCredential | null;\n\n\t\t\t\t\t\t\t\tif (!identityCredential?.token) {\n\t\t\t\t\t\t\t\t\t// Notify the caller that the prompt resulted in no token.\n\t\t\t\t\t\t\t\t\topts?.onPromptNotification?.(undefined);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tawait callback(identityCredential.token);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\tconsole.error(\"Error during FedCM callback:\", error);\n\t\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} catch (error: any) {\n\t\t\t\t\t\t\t\tif (error?.code && (error.code === 19 || error.code === 20)) {\n\t\t\t\t\t\t\t\t\t// Notify the caller that the prompt was closed/dismissed.\n\t\t\t\t\t\t\t\t\topts?.onPromptNotification?.(undefined);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\toneTap: () => {\n\t\t\t\t\t\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\t\t\t\t\t\tlet isResolved = false;\n\t\t\t\t\t\t\t\tconst baseDelay = options.promptOptions?.baseDelay ?? 1000;\n\t\t\t\t\t\t\t\tconst maxAttempts = options.promptOptions?.maxAttempts ?? 5;\n\n\t\t\t\t\t\t\t\twindow.google?.accounts.id.initialize({\n\t\t\t\t\t\t\t\t\tclient_id: options.clientId,\n\t\t\t\t\t\t\t\t\tcallback: async (response: { credential: string }) => {\n\t\t\t\t\t\t\t\t\t\tisResolved = true;\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tawait callback(response.credential);\n\t\t\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\t\t\tconsole.error(\"Error during One Tap callback:\", error);\n\t\t\t\t\t\t\t\t\t\t\treject(error);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tauto_select: autoSelect,\n\t\t\t\t\t\t\t\t\tcancel_on_tap_outside: cancelOnTapOutside,\n\t\t\t\t\t\t\t\t\tcontext: contextValue,\n\t\t\t\t\t\t\t\t\tux_mode: opts?.uxMode || \"popup\",\n\t\t\t\t\t\t\t\t\tnonce: opts?.nonce,\n\t\t\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t\t\t * @see {@link https://developers.google.com/identity/gsi/web/guides/overview}\n\t\t\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\t\t\titp_support: true,\n\n\t\t\t\t\t\t\t\t\t...options.additionalOptions,\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tconst handlePrompt = (attempt: number) => {\n\t\t\t\t\t\t\t\t\tif (isResolved) return;\n\n\t\t\t\t\t\t\t\t\twindow.google?.accounts.id.prompt((notification: any) => {\n\t\t\t\t\t\t\t\t\t\tif (isResolved) return;\n\n\t\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t\tnotification.isDismissedMoment &&\n\t\t\t\t\t\t\t\t\t\t\tnotification.isDismissedMoment()\n\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\tconst reason = notification.getDismissedReason?.();\n\t\t\t\t\t\t\t\t\t\t\tif (noRetryReasons.dismissed.includes(reason)) {\n\t\t\t\t\t\t\t\t\t\t\t\topts?.onPromptNotification?.(notification);\n\t\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tif (attempt < maxAttempts) {\n\t\t\t\t\t\t\t\t\t\t\t\tconst delay = Math.pow(2, attempt) * baseDelay;\n\t\t\t\t\t\t\t\t\t\t\t\tsetTimeout(() => handlePrompt(attempt + 1), delay);\n\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\topts?.onPromptNotification?.(notification);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\t\t\t\t\tnotification.isSkippedMoment &&\n\t\t\t\t\t\t\t\t\t\t\tnotification.isSkippedMoment()\n\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\tconst reason = notification.getSkippedReason?.();\n\t\t\t\t\t\t\t\t\t\t\tif (noRetryReasons.skipped.includes(reason)) {\n\t\t\t\t\t\t\t\t\t\t\t\topts?.onPromptNotification?.(notification);\n\t\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tif (attempt < maxAttempts) {\n\t\t\t\t\t\t\t\t\t\t\t\tconst delay = Math.pow(2, attempt) * baseDelay;\n\t\t\t\t\t\t\t\t\t\t\t\tsetTimeout(() => handlePrompt(attempt + 1), delay);\n\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\topts?.onPromptNotification?.(notification);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\thandlePrompt(0);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\n\t\t\t\t\tif (isRequestInProgress) {\n\t\t\t\t\t\tisRequestInProgress?.abort();\n\t\t\t\t\t}\n\t\t\t\t\tisRequestInProgress = new AbortController();\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst client =\n\t\t\t\t\t\t\toptions.promptOptions?.fedCM === false || !isFedCMSupported()\n\t\t\t\t\t\t\t\t? \"oneTap\"\n\t\t\t\t\t\t\t\t: \"fedCM\";\n\t\t\t\t\t\tif (client === \"oneTap\") {\n\t\t\t\t\t\t\tawait loadGoogleScript();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tawait clients[client]();\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconsole.error(\"Error during Google One Tap flow:\", error);\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tisRequestInProgress = null;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\tgetAtoms($fetch) {\n\t\t\treturn {};\n\t\t},\n\t} satisfies BetterAuthClientPlugin;\n};\n\nconst loadGoogleScript = (): Promise<void> => {\n\treturn new Promise((resolve) => {\n\t\tif (window.googleScriptInitialized) {\n\t\t\tresolve();\n\t\t\treturn;\n\t\t}\n\n\t\tconst script = document.createElement(\"script\");\n\t\tscript.src = \"https://accounts.google.com/gsi/client\";\n\t\tscript.async = true;\n\t\tscript.defer = true;\n\t\tscript.onload = () => {\n\t\t\twindow.googleScriptInitialized = true;\n\t\t\tresolve();\n\t\t};\n\t\tdocument.head.appendChild(script);\n\t});\n};\n"],"mappings":"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"}