From 5d6937c9f952f5dc586439b7fcf053abc9fcf320 Mon Sep 17 00:00:00 2001 From: Dimitris Klouvas Date: Tue, 6 Feb 2024 14:49:30 +0200 Subject: [PATCH] fix(clerk-js): Make email-link return to application instead of AP (#2727) * fix(clerk-js): Use signInUrl from context as email-link redirectUrl The signInUrl used in email-link will be retrieved from the props or context or repo-level or display config (with the same priority as listed here). In applications that the sign-in url is defined the email-link verification will redirect to the application without passing through the AP first. This results in fixing the handshake for email- link flows. Note: Applications using the signInUrl from the Dashboard settings, will not support the handshake flow and would require an additional redirect to FAPI/v1/client/handshake on email-link verification to work. * fix(clerk-js): Make path-based routing the default in redirects * fix(clerk-js): Fix type --------- Co-authored-by: Nikos Douvlis --- .changeset/tiny-beds-yell.md | 5 +++++ .../src/ui/common/__tests__/redirects.test.ts | 10 +++++----- packages/clerk-js/src/ui/common/redirects.ts | 4 ++-- .../SignIn/SignInFactorOneEmailLinkCard.tsx | 4 ++-- .../components/SignIn/__tests__/SignInStart.test.tsx | 2 +- .../src/ui/contexts/ClerkUIComponentsContext.tsx | 11 +++++++++-- 6 files changed, 24 insertions(+), 12 deletions(-) create mode 100644 .changeset/tiny-beds-yell.md diff --git a/.changeset/tiny-beds-yell.md b/.changeset/tiny-beds-yell.md new file mode 100644 index 0000000000..a4c2337f7c --- /dev/null +++ b/.changeset/tiny-beds-yell.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-js': minor +--- + +Use signInUrl from props/ context / repo-level to construct a redirectUrl in email-link flow. diff --git a/packages/clerk-js/src/ui/common/__tests__/redirects.test.ts b/packages/clerk-js/src/ui/common/__tests__/redirects.test.ts index 31cff699ef..9eb17dc5ca 100644 --- a/packages/clerk-js/src/ui/common/__tests__/redirects.test.ts +++ b/packages/clerk-js/src/ui/common/__tests__/redirects.test.ts @@ -1,8 +1,8 @@ import { buildEmailLinkRedirectUrl, buildSSOCallbackURL } from '../redirects'; describe('buildEmailLinkRedirectUrl(routing, baseUrl)', () => { - it('handles empty routing strategy based routing ', function () { - expect(buildEmailLinkRedirectUrl({ path: '', authQueryString: '' } as any, '')).toBe('http://localhost/#/verify'); + it('defaults to path based routing strategy on empty routing', function () { + expect(buildEmailLinkRedirectUrl({ path: '', authQueryString: '' } as any, '')).toBe('http://localhost/verify'); }); it('returns the magic link redirect url for components using path based routing ', function () { @@ -129,10 +129,10 @@ describe('buildEmailLinkRedirectUrl(routing, baseUrl)', () => { describe('buildSSOCallbackURL(ctx, baseUrl)', () => { it('returns the SSO callback URL based on sign in|up component routing or the provided base URL', () => { // Default callback URLS - expect(buildSSOCallbackURL({}, '')).toBe('http://localhost/#/sso-callback'); - expect(buildSSOCallbackURL({}, 'http://test.host')).toBe('http://localhost/#/sso-callback'); + expect(buildSSOCallbackURL({}, '')).toBe('http://localhost/sso-callback'); + expect(buildSSOCallbackURL({}, 'http://test.host')).toBe('http://localhost/sso-callback'); expect(buildSSOCallbackURL({ authQueryString: 'redirect_url=%2Ffoo' }, 'http://test.host')).toBe( - 'http://localhost/#/sso-callback?redirect_url=%2Ffoo', + 'http://localhost/sso-callback?redirect_url=%2Ffoo', ); // Components mounted with hash routing diff --git a/packages/clerk-js/src/ui/common/redirects.ts b/packages/clerk-js/src/ui/common/redirects.ts index c5bf2858cf..a610f24d3d 100644 --- a/packages/clerk-js/src/ui/common/redirects.ts +++ b/packages/clerk-js/src/ui/common/redirects.ts @@ -42,11 +42,11 @@ type BuildRedirectUrlParams = { }; const buildRedirectUrl = ({ routing, authQueryString, baseUrl, path, endpoint }: BuildRedirectUrlParams): string => { - if (!routing || routing === 'hash') { + if (routing === 'hash') { return buildHashBasedUrl(authQueryString, endpoint); } - if (routing === 'path') { + if (!routing || routing === 'path') { return buildPathBasedUrl(path || '', authQueryString, endpoint); } diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneEmailLinkCard.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneEmailLinkCard.tsx index 848196556b..a8f9609733 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneEmailLinkCard.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneEmailLinkCard.tsx @@ -5,7 +5,7 @@ import React from 'react'; import { EmailLinkStatusCard } from '../../common'; import { buildEmailLinkRedirectUrl } from '../../common/redirects'; -import { useCoreSignIn, useEnvironment, useSignInContext } from '../../contexts'; +import { useCoreSignIn, useSignInContext } from '../../contexts'; import { Flow, localizationKeys, useLocalizations } from '../../customizables'; import type { VerificationCodeCardProps } from '../../elements'; import { VerificationLinkCard } from '../../elements'; @@ -25,7 +25,7 @@ export const SignInFactorOneEmailLinkCard = (props: SignInFactorOneEmailLinkCard const card = useCardState(); const signIn = useCoreSignIn(); const signInContext = useSignInContext(); - const { signInUrl } = useEnvironment().displayConfig; + const { signInUrl } = signInContext; const { navigate } = useRouter(); const { navigateAfterSignIn } = useSignInContext(); const { setActive } = useClerk(); diff --git a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx index e0e978cce4..7624c83a93 100644 --- a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx @@ -139,7 +139,7 @@ describe('SignInStart', () => { expect(fixtures.signIn.create).toHaveBeenCalled(); expect(fixtures.signIn.authenticateWithRedirect).toHaveBeenCalledWith({ strategy: 'saml', - redirectUrl: 'http://localhost/#/sso-callback?redirect_url=http%3A%2F%2Flocalhost%2F', + redirectUrl: 'http://localhost/sso-callback?redirect_url=http%3A%2F%2Flocalhost%2F', redirectUrlComplete: '/', }); }); diff --git a/packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx b/packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx index 4770346278..3c108b2646 100644 --- a/packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx +++ b/packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx @@ -118,6 +118,7 @@ export type SignInContextType = SignInCtx & { navigateAfterSignIn: () => any; queryParams: ParsedQs; signUpUrl: string; + signInUrl: string; signUpContinueUrl: string; authQueryString: string | null; }; @@ -157,24 +158,30 @@ export const useSignInContext = (): SignInContextType => { const navigateAfterSignIn = () => navigate(afterSignInUrl); - let signUpUrl = pickRedirectionProp('signUpUrl', { ctx, options, displayConfig }, false); - // Add query strings to the sign in URL const authQs = buildAuthQueryString({ afterSignInUrl: afterSignInUrl, afterSignUpUrl: afterSignUpUrl, displayConfig: displayConfig, }); + + let signUpUrl = pickRedirectionProp('signUpUrl', { ctx, options, displayConfig }, false); if (authQs && ctx.routing !== 'virtual') { signUpUrl += `#/?${authQs}`; } + let signInUrl = pickRedirectionProp('signInUrl', { ctx, options, displayConfig }, false); + if (authQs && ctx.routing !== 'virtual') { + signInUrl += `#/?${authQs}`; + } + const signUpContinueUrl = buildURL({ base: signUpUrl, hashPath: '/continue' }, { stringify: true }); return { ...ctx, componentName, signUpUrl, + signInUrl, afterSignInUrl, afterSignUpUrl, navigateAfterSignIn,