Skip to content

Commit 6b17d98

Browse files
committed
Fix navigation for SSO to maintain path and hash routing
1 parent e012c88 commit 6b17d98

File tree

8 files changed

+74
-55
lines changed

8 files changed

+74
-55
lines changed

packages/clerk-js/src/core/clerk.ts

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,7 @@ import {
151151
Organization,
152152
Waitlist,
153153
} from './resources/internal';
154-
import {
155-
INTERNAL_SESSION_TASK_ROUTE_BY_KEY,
156-
navigateIfTaskExists,
157-
warnMissingPendingTaskHandlers,
158-
} from './sessionTasks';
154+
import { buildTaskUrl, INTERNAL_SESSION_TASK_ROUTE_BY_KEY, warnMissingPendingTaskHandlers } from './sessionTasks';
159155
import { State } from './state';
160156
import { warnings } from './warnings';
161157

@@ -1795,6 +1791,9 @@ export class Clerk implements ClerkInterface {
17951791
sessionId: signIn.createdSessionId,
17961792
};
17971793

1794+
const signInUrl = params.signInUrl || displayConfig.signInUrl;
1795+
const signUpUrl = params.signUpUrl || displayConfig.signUpUrl;
1796+
17981797
const makeNavigate = (to: string) => () => navigate(to);
17991798

18001799
const navigateToSignIn = makeNavigate(params.signInUrl || displayConfig.signInUrl);
@@ -1852,23 +1851,28 @@ export class Clerk implements ClerkInterface {
18521851
});
18531852
};
18541853

1855-
const setActiveNavigate = async ({ session, redirectUrl }: { session: SessionResource; redirectUrl: string }) => {
1854+
const setActiveNavigate = async ({
1855+
session,
1856+
baseUrl,
1857+
redirectUrl,
1858+
}: {
1859+
session: SessionResource;
1860+
baseUrl: string;
1861+
redirectUrl: string;
1862+
}) => {
18561863
if (!session.currentTask) {
18571864
await this.navigate(redirectUrl);
18581865
return;
18591866
}
18601867

1861-
await navigateIfTaskExists(session, {
1862-
baseUrl: params.signInUrl ?? displayConfig.signInUrl,
1863-
navigate: this.navigate,
1864-
});
1868+
await navigate(params.taskUrl ?? buildTaskUrl(session.currentTask, { baseUrl }));
18651869
};
18661870

18671871
if (si.status === 'complete') {
18681872
return this.setActive({
18691873
session: si.sessionId,
18701874
navigate: async ({ session }) => {
1871-
await setActiveNavigate({ session, redirectUrl: redirectUrls.getAfterSignInUrl() });
1875+
await setActiveNavigate({ session, baseUrl: signInUrl, redirectUrl: redirectUrls.getAfterSignInUrl() });
18721876
},
18731877
});
18741878
}
@@ -1883,7 +1887,7 @@ export class Clerk implements ClerkInterface {
18831887
return this.setActive({
18841888
session: res.createdSessionId,
18851889
navigate: async ({ session }) => {
1886-
await setActiveNavigate({ session, redirectUrl: redirectUrls.getAfterSignInUrl() });
1890+
await setActiveNavigate({ session, baseUrl: signInUrl, redirectUrl: redirectUrls.getAfterSignInUrl() });
18871891
},
18881892
});
18891893
case 'needs_first_factor':
@@ -1934,7 +1938,7 @@ export class Clerk implements ClerkInterface {
19341938
return this.setActive({
19351939
session: res.createdSessionId,
19361940
navigate: async ({ session }) => {
1937-
await setActiveNavigate({ session, redirectUrl: redirectUrls.getAfterSignUpUrl() });
1941+
await setActiveNavigate({ session, baseUrl: signUpUrl, redirectUrl: redirectUrls.getAfterSignUpUrl() });
19381942
},
19391943
});
19401944
case 'missing_requirements':
@@ -1948,7 +1952,7 @@ export class Clerk implements ClerkInterface {
19481952
return this.setActive({
19491953
session: su.sessionId,
19501954
navigate: async ({ session }) => {
1951-
await setActiveNavigate({ session, redirectUrl: redirectUrls.getAfterSignUpUrl() });
1955+
await setActiveNavigate({ session, baseUrl: signUpUrl, redirectUrl: redirectUrls.getAfterSignUpUrl() });
19521956
},
19531957
});
19541958
}
@@ -1974,7 +1978,7 @@ export class Clerk implements ClerkInterface {
19741978
return this.setActive({
19751979
session: sessionId,
19761980
navigate: async ({ session }) => {
1977-
await setActiveNavigate({ session, redirectUrl: redirectUrls.getAfterSignInUrl() });
1981+
await setActiveNavigate({ session, baseUrl: signInUrl, redirectUrl: redirectUrls.getAfterSignInUrl() });
19781982
},
19791983
});
19801984
}
@@ -1989,11 +1993,7 @@ export class Clerk implements ClerkInterface {
19891993
}
19901994

19911995
if (this.session?.currentTask) {
1992-
await navigateIfTaskExists(this.session, {
1993-
baseUrl: params.signInUrl ?? displayConfig.signInUrl,
1994-
navigate: this.navigate,
1995-
});
1996-
return;
1996+
return this.navigate(params.taskUrl ?? this.buildTasksUrl());
19971997
}
19981998

19991999
return navigateToSignIn();
@@ -2170,10 +2170,11 @@ export class Clerk implements ClerkInterface {
21702170
return;
21712171
}
21722172

2173-
await navigateIfTaskExists(session, {
2174-
baseUrl: displayConfig.signInUrl,
2175-
navigate: this.navigate,
2176-
});
2173+
await this.navigate(
2174+
buildTaskUrl(session.currentTask, {
2175+
baseUrl: displayConfig.signInUrl,
2176+
}),
2177+
);
21772178
};
21782179

21792180
switch (signInOrSignUp.status) {

packages/clerk-js/src/core/sessionTasks.ts

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { logger } from '@clerk/shared/logger';
2-
import type { ClerkOptions, SessionResource, SessionTask, SetActiveParams } from '@clerk/types';
2+
import type { ClerkOptions, SessionTask, SetActiveParams } from '@clerk/types';
33

4-
import { buildURL, forwardClerkQueryParams } from '../utils';
4+
import { buildRedirectUrl } from '@/ui/common';
5+
import { buildURL } from '@/utils';
56

67
/**
78
* @internal
@@ -10,41 +11,39 @@ export const INTERNAL_SESSION_TASK_ROUTE_BY_KEY: Record<SessionTask['key'], stri
1011
'choose-organization': 'choose-organization',
1112
} as const;
1213

14+
const getTaskEndpoint = (task: SessionTask) => `/tasks/${INTERNAL_SESSION_TASK_ROUTE_BY_KEY[task.key]}`;
15+
1316
/**
1417
* @internal
1518
*/
16-
export function buildTaskUrl(task: SessionTask, opts: Pick<Parameters<typeof buildURL>[0], 'base'>) {
17-
const params = forwardClerkQueryParams();
19+
export function buildTaskRedirectUrl(
20+
task: SessionTask,
21+
opts: Omit<Parameters<typeof buildRedirectUrl>[0], 'endpoint'>,
22+
) {
23+
const { path, routing, baseUrl, authQueryString } = opts;
24+
const endpoint = getTaskEndpoint(task);
1825

19-
return buildURL(
20-
{
21-
base: opts.base,
22-
hashPath: `/tasks/${INTERNAL_SESSION_TASK_ROUTE_BY_KEY[task.key]}`,
23-
searchParams: params,
24-
},
25-
{ stringify: true },
26-
);
26+
return buildRedirectUrl({
27+
baseUrl,
28+
path,
29+
routing,
30+
endpoint,
31+
authQueryString,
32+
});
2733
}
2834

2935
/**
3036
* @internal
3137
*/
32-
export function navigateIfTaskExists(
33-
session: SessionResource,
38+
export function buildTaskUrl(
39+
task: SessionTask,
3440
{
35-
navigate,
3641
baseUrl,
3742
}: {
38-
navigate: (to: string) => Promise<unknown>;
3943
baseUrl: string;
4044
},
4145
) {
42-
const currentTask = session.currentTask;
43-
if (!currentTask) {
44-
return;
45-
}
46-
47-
return navigate(buildTaskUrl(currentTask, { base: baseUrl }));
46+
return buildURL({ base: baseUrl, hashPath: getTaskEndpoint(task) }, { stringify: true });
4847
}
4948

5049
export function warnMissingPendingTaskHandlers(options: Record<string, unknown>) {

packages/clerk-js/src/ui/components/SignIn/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ function SignInRoutes(): JSX.Element {
6363
</Route>
6464
<Route path='sso-callback'>
6565
<SignInSSOCallback
66+
taskUrl={signInContext.taskUrl}
6667
signUpUrl={signInContext.signUpUrl}
6768
signInUrl={signInContext.signInUrl}
6869
signInForceRedirectUrl={signInContext.afterSignInUrl}

packages/clerk-js/src/ui/components/SignUp/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ function SignUpRoutes(): JSX.Element {
4545
</Route>
4646
<Route path='sso-callback'>
4747
<SignUpSSOCallback
48+
taskUrl={signUpContext.taskUrl}
4849
signUpUrl={signUpContext.signUpUrl}
4950
signInUrl={signUpContext.signInUrl}
5051
signUpForceRedirectUrl={signUpContext.afterSignUpUrl}

packages/clerk-js/src/ui/components/UserButton/useMultisessionActions.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useClerk } from '@clerk/shared/react';
22
import type { SignedInSessionResource, UserButtonProps, UserResource } from '@clerk/types';
33

4-
import { navigateIfTaskExists } from '@/core/sessionTasks';
4+
import { buildTaskUrl } from '@/core/sessionTasks';
55
import { useEnvironment } from '@/ui/contexts';
66
import { useCardState } from '@/ui/elements/contexts';
77
import { sleep } from '@/ui/utils/sleep';
@@ -81,10 +81,13 @@ export const useMultisessionActions = (opts: UseMultisessionActionsParams) => {
8181
return;
8282
}
8383

84-
await navigateIfTaskExists(session, {
85-
baseUrl: opts.signInUrl ?? displayConfig.signInUrl,
86-
navigate,
87-
});
84+
if (session.currentTask) {
85+
await navigate(
86+
buildTaskUrl(session.currentTask, {
87+
baseUrl: opts.signInUrl ?? displayConfig.signInUrl,
88+
}),
89+
);
90+
}
8891
},
8992
}).finally(() => {
9093
card.setIdle();

packages/clerk-js/src/ui/contexts/components/SignIn.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { isAbsoluteUrl } from '@clerk/shared/url';
33
import type { SessionResource } from '@clerk/types';
44
import { createContext, useContext, useMemo } from 'react';
55

6-
import { buildTaskUrl, INTERNAL_SESSION_TASK_ROUTE_BY_KEY } from '@/core/sessionTasks';
6+
import { buildTaskRedirectUrl, INTERNAL_SESSION_TASK_ROUTE_BY_KEY } from '@/core/sessionTasks';
77

88
import { SIGN_IN_INITIAL_VALUE_KEYS } from '../../../core/constants';
99
import { buildURL } from '../../../utils';
@@ -131,7 +131,12 @@ export const useSignInContext = (): SignInContextType => {
131131

132132
const taskUrl = clerk.session?.currentTask
133133
? (clerk.__internal_getOption('taskUrls')?.[clerk.session?.currentTask.key] ??
134-
buildTaskUrl(clerk.session?.currentTask, { base: signInUrl }))
134+
buildTaskRedirectUrl(clerk.session?.currentTask, {
135+
routing: ctx.routing,
136+
baseUrl: signInUrl,
137+
authQueryString,
138+
path: ctx.path,
139+
}))
135140
: null;
136141

137142
return {

packages/clerk-js/src/ui/contexts/components/SignUp.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { isAbsoluteUrl } from '@clerk/shared/url';
33
import type { SessionResource } from '@clerk/types';
44
import { createContext, useContext, useMemo } from 'react';
55

6-
import { buildTaskUrl, INTERNAL_SESSION_TASK_ROUTE_BY_KEY } from '@/core/sessionTasks';
6+
import { buildTaskRedirectUrl, INTERNAL_SESSION_TASK_ROUTE_BY_KEY } from '@/core/sessionTasks';
77

88
import { SIGN_UP_INITIAL_VALUE_KEYS } from '../../../core/constants';
99
import { buildURL } from '../../../utils';
@@ -126,7 +126,12 @@ export const useSignUpContext = (): SignUpContextType => {
126126

127127
const taskUrl = clerk.session?.currentTask
128128
? (clerk.__internal_getOption('taskUrls')?.[clerk.session?.currentTask.key] ??
129-
buildTaskUrl(clerk.session?.currentTask, { base: signUpUrl }))
129+
buildTaskRedirectUrl(clerk.session?.currentTask, {
130+
routing: ctx.routing,
131+
baseUrl: signUpUrl,
132+
authQueryString,
133+
path: ctx.path,
134+
}))
130135
: null;
131136

132137
return {

packages/types/src/clerk.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,10 @@ export type HandleOAuthCallbackParams = TransferableOption &
926926
* Full URL or path to navigate to after requesting phone verification.
927927
*/
928928
verifyPhoneNumberUrl?: string | null;
929+
/**
930+
* Full URL or path where to navigate for the current task.
931+
*/
932+
taskUrl?: string | null;
929933
/**
930934
* The underlying resource to optionally reload before processing an OAuth callback.
931935
*/

0 commit comments

Comments
 (0)