Skip to content

Commit e19feaa

Browse files
committed
fix(ui): route an OAuth transfer to the sign-up continue step over a native transport
1 parent 5fac41b commit e19feaa

3 files changed

Lines changed: 59 additions & 3 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/ui': patch
3+
---
4+
5+
Route an OAuth transfer to the sign-up continue step when sign-in uses a native OAuth transport. The callback previously navigated with hash-style URLs (`<sign-up-url>#/continue`) that the in-place component router cannot resolve, landing transferred sign-ups on the start card where submitting created a fresh sign-up without the verified external account.

‎packages/ui/src/components/SignIn/__tests__/buildOAuthCallbackParams.test.ts‎

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,57 @@ describe('buildSignInOAuthTransportCallbackParams', () => {
5555
unsafeMetadata: { a: 1 },
5656
} as any;
5757

58+
const origin = window.location.origin;
59+
5860
expect(buildSignInOAuthTransportCallbackParams(ctx)).toEqual({
5961
signUpUrl: '/sign-up',
6062
signInUrl: '/sign-in',
6163
signInForceRedirectUrl: '/after-in',
6264
signUpForceRedirectUrl: '/after-up',
63-
continueSignUpUrl: '/continue',
6465
transferable: true,
6566
firstFactorUrl: 'factor-one',
6667
secondFactorUrl: 'factor-two',
6768
resetPasswordUrl: 'reset-password',
68-
// Relative to the SignIn start route; the sign-up gate URL stays absolute (combined-aware).
6969
signInProtectCheckUrl: 'protect-check',
70-
signUpProtectCheckUrl: '/sign-up-protect-check',
70+
// Sign-up steps are path routes on the sign-up component; hash-style URLs would lose their
71+
// hash in the virtual router and land a transferred sign-up on the start card.
72+
continueSignUpUrl: `${origin}/sign-up/continue`,
73+
verifyEmailAddressUrl: `${origin}/sign-up/verify-email-address`,
74+
verifyPhoneNumberUrl: `${origin}/sign-up/verify-phone-number`,
75+
signUpProtectCheckUrl: `${origin}/sign-up/protect-check`,
7176
unsafeMetadata: { a: 1 },
7277
});
7378
});
79+
80+
it('targets the virtual sign-up routes for modal transport callbacks', () => {
81+
const ctx = {
82+
signUpUrl: '/CLERK-ROUTER/VIRTUAL/sign-up',
83+
signInUrl: '/CLERK-ROUTER/VIRTUAL/sign-in',
84+
} as any;
85+
86+
const params = buildSignInOAuthTransportCallbackParams(ctx);
87+
const origin = window.location.origin;
88+
89+
expect(params.continueSignUpUrl).toBe(`${origin}/CLERK-ROUTER/VIRTUAL/sign-up/continue`);
90+
expect(params.verifyEmailAddressUrl).toBe(`${origin}/CLERK-ROUTER/VIRTUAL/sign-up/verify-email-address`);
91+
expect(params.verifyPhoneNumberUrl).toBe(`${origin}/CLERK-ROUTER/VIRTUAL/sign-up/verify-phone-number`);
92+
expect(params.signUpProtectCheckUrl).toBe(`${origin}/CLERK-ROUTER/VIRTUAL/sign-up/protect-check`);
93+
});
94+
95+
it('targets the embedded create subtree in the combined flow', () => {
96+
const ctx = {
97+
signUpUrl: '/sign-in#/create',
98+
signInUrl: '/sign-in',
99+
isCombinedFlow: true,
100+
} as any;
101+
102+
const params = buildSignInOAuthTransportCallbackParams(ctx);
103+
104+
expect(params.continueSignUpUrl).toBe('create/continue');
105+
expect(params.verifyEmailAddressUrl).toBe('create/verify-email-address');
106+
expect(params.verifyPhoneNumberUrl).toBe('create/verify-phone-number');
107+
expect(params.signUpProtectCheckUrl).toBe('create/protect-check');
108+
});
74109
});
75110

76111
describe('buildSignUpOAuthCallbackParams', () => {

‎packages/ui/src/components/SignIn/buildOAuthCallbackParams.ts‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { buildURL, trimTrailingSlash } from '@clerk/shared/internal/clerk-js/url';
12
import type { HandleOAuthCallbackParams } from '@clerk/shared/types';
23

34
import type { SignInContextType } from '../../contexts/components/SignIn';
@@ -23,12 +24,27 @@ export function buildSignInOAuthCallbackParams(ctx: SignInContextType): HandleOA
2324
}
2425

2526
export function buildSignInOAuthTransportCallbackParams(ctx: SignInContextType): HandleOAuthCallbackParams {
27+
// Path form, not `#/step`: the in-place component router matches on pathname only and would drop the hash.
28+
const signUpStepUrl = (step: string): string => {
29+
if (ctx.isCombinedFlow) {
30+
return `create/${step}`;
31+
}
32+
const url = buildURL({ base: ctx.signUpUrl }, { stringify: false });
33+
url.pathname = `${trimTrailingSlash(url.pathname)}/${step}`;
34+
url.hash = '';
35+
return url.href;
36+
};
37+
2638
return {
2739
...buildSignInOAuthCallbackParams(ctx),
2840
firstFactorUrl: 'factor-one',
2941
secondFactorUrl: 'factor-two',
3042
resetPasswordUrl: 'reset-password',
3143
signInProtectCheckUrl: 'protect-check',
44+
continueSignUpUrl: signUpStepUrl('continue'),
45+
verifyEmailAddressUrl: signUpStepUrl('verify-email-address'),
46+
verifyPhoneNumberUrl: signUpStepUrl('verify-phone-number'),
47+
signUpProtectCheckUrl: signUpStepUrl('protect-check'),
3248
};
3349
}
3450

0 commit comments

Comments
 (0)