diff --git a/.changeset/witty-hotels-add.md b/.changeset/witty-hotels-add.md new file mode 100644 index 00000000000..314fffa5f90 --- /dev/null +++ b/.changeset/witty-hotels-add.md @@ -0,0 +1,5 @@ +--- +'@clerk/backend': patch +--- + +Ensure `__clerk_synced` is removed from cross-origin return-back urls diff --git a/packages/backend/src/__tests__/createRedirect.test.ts b/packages/backend/src/__tests__/createRedirect.test.ts index 82e415e7064..ab23730aca6 100644 --- a/packages/backend/src/__tests__/createRedirect.test.ts +++ b/packages/backend/src/__tests__/createRedirect.test.ts @@ -99,6 +99,28 @@ describe('redirect(redirectAdapter)', () => { ); }); + it('removes __clerk_synced when cross-origin redirect', () => { + const returnBackUrl = 'https://current.url:3000/path?__clerk_synced=true&q=1#hash'; + const encodedUrl = 'https%3A%2F%2Fcurrent.url%3A3000%2Fpath%3Fq%3D1%23hash'; + const signUpUrl = 'https://lcl.dev/sign-up'; + + const redirectAdapterSpy = vi.fn().mockImplementation(_url => 'redirectAdapterValue'); + const { redirectToSignUp } = createRedirect({ + baseUrl: 'http://www.clerk.com', + devBrowserToken: 'deadbeef', + redirectAdapter: redirectAdapterSpy, + publishableKey: 'pk_test_Y2xlcmsubGNsLmRldiQ', + sessionStatus: 'active', + signUpUrl, + }); + + const result = redirectToSignUp({ returnBackUrl }); + expect(result).toBe('redirectAdapterValue'); + expect(redirectAdapterSpy).toHaveBeenCalledWith( + `${signUpUrl}?redirect_url=${encodedUrl}&__clerk_db_jwt=deadbeef`, + ); + }); + it('returns path based url with development (kima) publishableKey (with staging Clerk) but without signUpUrl to redirectToSignUp', () => { const redirectAdapterSpy = vi.fn().mockImplementation(_url => 'redirectAdapterValue'); const { redirectToSignUp } = createRedirect({ @@ -320,5 +342,25 @@ describe('redirect(redirectAdapter)', () => { `https://included.katydid-92.accounts.dev/sign-up/tasks?redirect_url=${encodedUrl}&__clerk_db_jwt=deadbeef`, ); }); + + it('removes __clerk_synced when cross-origin redirect', () => { + const returnBackUrl = 'https://current.url:3000/path?__clerk_synced=true&q=1#hash'; + const encodedUrl = 'https%3A%2F%2Fcurrent.url%3A3000%2Fpath%3Fq%3D1%23hash'; + + const redirectAdapterSpy = vi.fn().mockImplementation(_url => 'redirectAdapterValue'); + const { redirectToSignUp } = createRedirect({ + baseUrl: 'http://www.clerk.com', + devBrowserToken: 'deadbeef', + redirectAdapter: redirectAdapterSpy, + publishableKey: 'pk_test_Y2xlcmsubGNsLmRldiQ', + sessionStatus: 'pending', + }); + + const result = redirectToSignUp({ returnBackUrl }); + expect(result).toBe('redirectAdapterValue'); + expect(redirectAdapterSpy).toHaveBeenCalledWith( + `https://accounts.lcl.dev/sign-up/tasks?redirect_url=${encodedUrl}&__clerk_db_jwt=deadbeef`, + ); + }); }); }); diff --git a/packages/backend/src/createRedirect.ts b/packages/backend/src/createRedirect.ts index 90dd4ae5475..07f2f6b8123 100644 --- a/packages/backend/src/createRedirect.ts +++ b/packages/backend/src/createRedirect.ts @@ -17,12 +17,17 @@ const buildUrl = ( const baseUrl = new URL(_baseUrl); const returnBackUrl = _returnBackUrl ? new URL(_returnBackUrl, baseUrl) : undefined; const res = new URL(_targetUrl, baseUrl); + const isCrossOriginRedirect = `${baseUrl.hostname}:${baseUrl.port}` !== `${res.hostname}:${res.port}`; if (returnBackUrl) { + if (isCrossOriginRedirect) { + returnBackUrl.searchParams.delete(constants.QueryParameters.ClerkSynced); + } + res.searchParams.set('redirect_url', returnBackUrl.toString()); } // For cross-origin redirects, we need to pass the dev browser token for URL session syncing - if (_devBrowserToken && baseUrl.hostname !== res.hostname) { + if (isCrossOriginRedirect && _devBrowserToken) { res.searchParams.set(constants.QueryParameters.DevBrowser, _devBrowserToken); } return res.toString();