Skip to content

Commit daa5c4a

Browse files
committed
fix: preserve enterprise sso sign-in reuse
1 parent 40261a6 commit daa5c4a

2 files changed

Lines changed: 63 additions & 6 deletions

File tree

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,11 +1145,15 @@ class SignInFuture implements SignInFutureResource {
11451145
routes.actionCompleteRedirectUrl = wrappedRoutes.redirectUrl;
11461146
}
11471147

1148-
await this._create({
1149-
strategy,
1150-
...routes,
1151-
identifier,
1152-
});
1148+
const shouldCreateSignIn = !this.#resource.id || strategy !== 'enterprise_sso';
1149+
1150+
if (shouldCreateSignIn) {
1151+
await this._create({
1152+
strategy,
1153+
...routes,
1154+
identifier,
1155+
});
1156+
}
11531157

11541158
if (strategy === 'enterprise_sso') {
11551159
await this.#resource.__internal_basePost({

packages/clerk-js/src/core/resources/__tests__/SignIn.test.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2110,6 +2110,59 @@ describe('SignIn', () => {
21102110
});
21112111
});
21122112

2113+
it('reuses an existing ticket sign-in when preparing enterprise SSO', async () => {
2114+
vi.stubGlobal('window', { location: { origin: 'https://example.com' } });
2115+
2116+
SignIn.clerk = {
2117+
buildUrlWithAuth: vi.fn().mockReturnValue('https://example.com/sso-callback'),
2118+
__internal_environment: {
2119+
displayConfig: {
2120+
captchaOauthBypass: [],
2121+
},
2122+
},
2123+
} as any;
2124+
2125+
const mockFetch = vi
2126+
.fn()
2127+
.mockResolvedValueOnce({
2128+
client: null,
2129+
response: {
2130+
id: 'signin_ticket',
2131+
status: 'needs_first_factor',
2132+
supported_first_factors: [{ strategy: 'enterprise_sso' }],
2133+
},
2134+
})
2135+
.mockResolvedValueOnce({
2136+
client: null,
2137+
response: {
2138+
id: 'signin_ticket',
2139+
first_factor_verification: {
2140+
status: 'unverified',
2141+
external_verification_redirect_url: 'https://sso.example.com/auth',
2142+
},
2143+
},
2144+
});
2145+
BaseResource._fetch = mockFetch;
2146+
2147+
const signIn = new SignIn();
2148+
await signIn.__internal_future.ticket({ ticket: 'ticket_123' });
2149+
await signIn.__internal_future.sso({
2150+
strategy: 'enterprise_sso',
2151+
redirectUrl: 'https://complete.example.com',
2152+
redirectCallbackUrl: '/sso-callback',
2153+
});
2154+
2155+
expect(mockFetch).toHaveBeenNthCalledWith(2, {
2156+
method: 'POST',
2157+
path: '/client/sign_ins/signin_ticket/prepare_first_factor',
2158+
body: {
2159+
strategy: 'enterprise_sso',
2160+
redirectUrl: 'https://example.com/sso-callback',
2161+
actionCompleteRedirectUrl: 'https://complete.example.com',
2162+
},
2163+
});
2164+
});
2165+
21132166
it('handles relative redirectUrl by converting to absolute', async () => {
21142167
vi.stubGlobal('window', { location: { origin: 'https://example.com' } });
21152168

@@ -2153,7 +2206,7 @@ describe('SignIn', () => {
21532206
});
21542207
});
21552208

2156-
it("creates a fresh sign-in on every sso() call, even when a prior provider's redirect is still pending", async () => {
2209+
it('creates a new OAuth sign-in when retrying after a previous provider redirect was abandoned', async () => {
21572210
vi.stubGlobal('window', { location: { origin: 'https://example.com' } });
21582211

21592212
const mockPopup = { location: { href: '' } } as Window;

0 commit comments

Comments
 (0)