diff --git a/.changeset/large-cars-flash.md b/.changeset/large-cars-flash.md new file mode 100644 index 00000000000..bf63912f4b9 --- /dev/null +++ b/.changeset/large-cars-flash.md @@ -0,0 +1,6 @@ +--- +'@clerk/clerk-js': patch +--- + +Bug fix: Use the correct returnBack url when GoogleOneTap remains open across navigations. +Previously it will only use the url that existed in the browser url bar at the time the component was initially rendered. diff --git a/packages/clerk-js/src/ui/components/GoogleOneTap/one-tap-start.tsx b/packages/clerk-js/src/ui/components/GoogleOneTap/one-tap-start.tsx index 22178821875..9d612da1e70 100644 --- a/packages/clerk-js/src/ui/components/GoogleOneTap/one-tap-start.tsx +++ b/packages/clerk-js/src/ui/components/GoogleOneTap/one-tap-start.tsx @@ -16,15 +16,6 @@ function _OneTapStart(): JSX.Element | null { const { navigate } = useRouter(); const ctx = useGoogleOneTapContext(); - const { - signInUrl, - signUpUrl, - continueSignUpUrl, - secondFactorUrl, - firstFactorUrl, - signUpForceRedirectUrl, - signInForceRedirectUrl, - } = ctx; async function oneTapCallback(response: GISCredentialResponse) { isPromptedRef.current = false; @@ -32,19 +23,7 @@ function _OneTapStart(): JSX.Element | null { const res = await clerk.authenticateWithGoogleOneTap({ token: response.credential, }); - await clerk.handleGoogleOneTapCallback( - res, - { - signInUrl, - signUpUrl, - continueSignUpUrl, - secondFactorUrl, - firstFactorUrl, - signUpForceRedirectUrl, - signInForceRedirectUrl, - }, - navigate, - ); + await clerk.handleGoogleOneTapCallback(res, ctx.generateCallbackUrls(window.location.href), navigate); } catch (e) { console.error(e); } diff --git a/packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx b/packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx index fa0cc67619a..2db870fb7ac 100644 --- a/packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx +++ b/packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx @@ -1,7 +1,7 @@ import { useClerk } from '@clerk/shared/react'; import { snakeToCamel } from '@clerk/shared/underscore'; -import type { OrganizationResource, UserResource } from '@clerk/types'; -import React, { useMemo } from 'react'; +import type { HandleOAuthCallbackParams, OrganizationResource, UserResource } from '@clerk/types'; +import React, { useCallback, useMemo } from 'react'; import { SIGN_IN_INITIAL_VALUE_KEYS, SIGN_UP_INITIAL_VALUE_KEYS } from '../../core/constants'; import { buildURL, createDynamicParamParser } from '../../utils'; @@ -506,67 +506,76 @@ export const useGoogleOneTapContext = () => { throw new Error('Clerk: useGoogleOneTapContext called outside GoogleOneTap.'); } - const redirectUrls = new RedirectUrls( - options, - { - ...ctx, - signInFallbackRedirectUrl: window.location.href, - signUpFallbackRedirectUrl: window.location.href, + const generateCallbackUrls = useCallback( + (returnBackUrl: string): HandleOAuthCallbackParams => { + const redirectUrls = new RedirectUrls( + options, + { + ...ctx, + signInFallbackRedirectUrl: returnBackUrl, + signUpFallbackRedirectUrl: returnBackUrl, + }, + queryParams, + ); + + let signUpUrl = options.signUpUrl || displayConfig.signUpUrl; + let signInUrl = options.signInUrl || displayConfig.signInUrl; + + const preservedParams = redirectUrls.getPreservedSearchParams(); + signInUrl = buildURL({ base: signInUrl, hashSearchParams: [queryParams, preservedParams] }, { stringify: true }); + signUpUrl = buildURL({ base: signUpUrl, hashSearchParams: [queryParams, preservedParams] }, { stringify: true }); + + const signInForceRedirectUrl = redirectUrls.getAfterSignInUrl(); + const signUpForceRedirectUrl = redirectUrls.getAfterSignUpUrl(); + + const signUpContinueUrl = buildURL( + { + base: signUpUrl, + hashPath: '/continue', + hashSearch: new URLSearchParams({ + sign_up_force_redirect_url: signUpForceRedirectUrl, + }).toString(), + }, + { stringify: true }, + ); + + const firstFactorUrl = buildURL( + { + base: signInUrl, + hashPath: '/factor-one', + hashSearch: new URLSearchParams({ + sign_in_force_redirect_url: signInForceRedirectUrl, + }).toString(), + }, + { stringify: true }, + ); + const secondFactorUrl = buildURL( + { + base: signInUrl, + hashPath: '/factor-two', + hashSearch: new URLSearchParams({ + sign_in_force_redirect_url: signInForceRedirectUrl, + }).toString(), + }, + { stringify: true }, + ); + + return { + signInUrl, + signUpUrl, + firstFactorUrl, + secondFactorUrl, + continueSignUpUrl: signUpContinueUrl, + signInForceRedirectUrl, + signUpForceRedirectUrl, + }; }, - queryParams, - ); - - let signUpUrl = options.signUpUrl || displayConfig.signUpUrl; - let signInUrl = options.signInUrl || displayConfig.signInUrl; - - const preservedParams = redirectUrls.getPreservedSearchParams(); - signInUrl = buildURL({ base: signInUrl, hashSearchParams: [queryParams, preservedParams] }, { stringify: true }); - signUpUrl = buildURL({ base: signUpUrl, hashSearchParams: [queryParams, preservedParams] }, { stringify: true }); - - const signInForceRedirectUrl = redirectUrls.getAfterSignInUrl(); - const signUpForceRedirectUrl = redirectUrls.getAfterSignUpUrl(); - - const signUpContinueUrl = buildURL( - { - base: signUpUrl, - hashPath: '/continue', - hashSearch: new URLSearchParams({ - sign_up_force_redirect_url: signUpForceRedirectUrl, - }).toString(), - }, - { stringify: true }, - ); - - const firstFactorUrl = buildURL( - { - base: signInUrl, - hashPath: '/factor-one', - hashSearch: new URLSearchParams({ - sign_in_force_redirect_url: signInForceRedirectUrl, - }).toString(), - }, - { stringify: true }, - ); - const secondFactorUrl = buildURL( - { - base: signInUrl, - hashPath: '/factor-two', - hashSearch: new URLSearchParams({ - sign_in_force_redirect_url: signInForceRedirectUrl, - }).toString(), - }, - { stringify: true }, + [ctx, displayConfig.signInUrl, displayConfig.signUpUrl, options, queryParams], ); return { ...ctx, componentName, - signInUrl, - signUpUrl, - firstFactorUrl, - secondFactorUrl, - continueSignUpUrl: signUpContinueUrl, - signInForceRedirectUrl, - signUpForceRedirectUrl, + generateCallbackUrls, }; };