From 54246ed94c670f30165cdb933ab6cdc7df7fa3f0 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Thu, 22 May 2025 13:14:10 -0500 Subject: [PATCH 1/3] ensure setActive emits the previous token before onBeforeSetActive() is fired --- .../clerk-js/src/core/__tests__/clerk.test.ts | 52 ++++++++++++++++++- packages/clerk-js/src/core/clerk.ts | 4 +- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/packages/clerk-js/src/core/__tests__/clerk.test.ts b/packages/clerk-js/src/core/__tests__/clerk.test.ts index b8238723cb1..cc6c0f611ff 100644 --- a/packages/clerk-js/src/core/__tests__/clerk.test.ts +++ b/packages/clerk-js/src/core/__tests__/clerk.test.ts @@ -166,7 +166,7 @@ describe('Clerk singleton', () => { getToken: jest.fn(), lastActiveToken: { getRawString: () => 'mocked-token' }, }; - let eventBusSpy; + let eventBusSpy: jest.SpyInstance; beforeEach(() => { eventBusSpy = jest.spyOn(eventBus, 'emit'); @@ -474,6 +474,56 @@ describe('Clerk singleton', () => { expect(sut.session).toMatchObject(mockSession); }); }); + + it('emits token update event with session token when switching sessions', async () => { + const mockSession1 = { + id: '1', + status: 'active', + user: {}, + touch: jest.fn(() => Promise.resolve()), + getToken: jest.fn(() => Promise.resolve('token-1')), + lastActiveToken: { getRawString: () => 'token-1' }, + }; + + const mockSession2 = { + id: '2', + status: 'active', + user: {}, + touch: jest.fn(() => Promise.resolve()), + getToken: jest.fn(() => Promise.resolve('token-2')), + lastActiveToken: { getRawString: () => 'token-2' }, + }; + + mockClientFetch.mockReturnValue( + Promise.resolve({ + signedInSessions: [mockSession1, mockSession2], + }), + ); + + const sut = new Clerk(productionPublishableKey); + await sut.load(); + + // Set initial session + await sut.setActive({ session: mockSession1 as any as ActiveSessionResource }); + + // Clear all previous calls to start fresh + eventBusSpy.mockClear(); + + // Switch to another session + await sut.setActive({ session: mockSession2 as any as ActiveSessionResource }); + + // Verify token update was emitted with the first session token + await waitFor(() => { + const [, { token }] = eventBusSpy.mock.lastCall; + expect(token?.getRawString()).toBe(mockSession1.lastActiveToken.getRawString()); + }); + + // Verify getToken was called from new session + await waitFor(() => { + expect(mockSession2.getToken).toHaveBeenCalled(); + expect(sut.session).toMatchObject(mockSession2); + }); + }); }); describe('with `pending` session status', () => { diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index cd0a44ba59b..c8476260037 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -1094,8 +1094,8 @@ export class Clerk implements ClerkInterface { return; } - if (session?.lastActiveToken) { - eventBus.emit(events.TokenUpdate, { token: session.lastActiveToken }); + if (this.session?.lastActiveToken) { + eventBus.emit(events.TokenUpdate, { token: this.session.lastActiveToken }); } /** From d9831b08acfe0f5d6983bc61dabf87e91b35da6a Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Thu, 22 May 2025 13:15:21 -0500 Subject: [PATCH 2/3] adds changeset --- .changeset/crazy-readers-flow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/crazy-readers-flow.md diff --git a/.changeset/crazy-readers-flow.md b/.changeset/crazy-readers-flow.md new file mode 100644 index 00000000000..945550aa36f --- /dev/null +++ b/.changeset/crazy-readers-flow.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-js': patch +--- + +Fix an issue where clerk-js was incorrectly emitting the new session's token during session switching. This impacts some applications that rely on Clerk's multi-session behavior. From 3f2af89658ec947e423ffe4f60cb26400bbed654 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Fri, 23 May 2025 14:03:32 -0500 Subject: [PATCH 3/3] Remove token update altogether --- .../clerk-js/src/core/__tests__/clerk.test.ts | 50 ------------------- packages/clerk-js/src/core/clerk.ts | 4 -- 2 files changed, 54 deletions(-) diff --git a/packages/clerk-js/src/core/__tests__/clerk.test.ts b/packages/clerk-js/src/core/__tests__/clerk.test.ts index cc6c0f611ff..e37e0fbdfd0 100644 --- a/packages/clerk-js/src/core/__tests__/clerk.test.ts +++ b/packages/clerk-js/src/core/__tests__/clerk.test.ts @@ -474,56 +474,6 @@ describe('Clerk singleton', () => { expect(sut.session).toMatchObject(mockSession); }); }); - - it('emits token update event with session token when switching sessions', async () => { - const mockSession1 = { - id: '1', - status: 'active', - user: {}, - touch: jest.fn(() => Promise.resolve()), - getToken: jest.fn(() => Promise.resolve('token-1')), - lastActiveToken: { getRawString: () => 'token-1' }, - }; - - const mockSession2 = { - id: '2', - status: 'active', - user: {}, - touch: jest.fn(() => Promise.resolve()), - getToken: jest.fn(() => Promise.resolve('token-2')), - lastActiveToken: { getRawString: () => 'token-2' }, - }; - - mockClientFetch.mockReturnValue( - Promise.resolve({ - signedInSessions: [mockSession1, mockSession2], - }), - ); - - const sut = new Clerk(productionPublishableKey); - await sut.load(); - - // Set initial session - await sut.setActive({ session: mockSession1 as any as ActiveSessionResource }); - - // Clear all previous calls to start fresh - eventBusSpy.mockClear(); - - // Switch to another session - await sut.setActive({ session: mockSession2 as any as ActiveSessionResource }); - - // Verify token update was emitted with the first session token - await waitFor(() => { - const [, { token }] = eventBusSpy.mock.lastCall; - expect(token?.getRawString()).toBe(mockSession1.lastActiveToken.getRawString()); - }); - - // Verify getToken was called from new session - await waitFor(() => { - expect(mockSession2.getToken).toHaveBeenCalled(); - expect(sut.session).toMatchObject(mockSession2); - }); - }); }); describe('with `pending` session status', () => { diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index c8476260037..e489ae5e4a9 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -1094,10 +1094,6 @@ export class Clerk implements ClerkInterface { return; } - if (this.session?.lastActiveToken) { - eventBus.emit(events.TokenUpdate, { token: this.session.lastActiveToken }); - } - /** * Hint to each framework, that the user will be signed out when `{session: null}` is provided. */