diff --git a/.changeset/wide-bags-mate.md b/.changeset/wide-bags-mate.md new file mode 100644 index 00000000000..1240480ac67 --- /dev/null +++ b/.changeset/wide-bags-mate.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-js': patch +--- + +Fixes a scenario where the session token would not immediately update after a call to `Clerk.session.touch()`. diff --git a/packages/clerk-js/bundlewatch.config.json b/packages/clerk-js/bundlewatch.config.json index bd7805ffc44..feb753cb8e9 100644 --- a/packages/clerk-js/bundlewatch.config.json +++ b/packages/clerk-js/bundlewatch.config.json @@ -1,7 +1,7 @@ { "files": [ { "path": "./dist/clerk.js", "maxSize": "610kB" }, - { "path": "./dist/clerk.browser.js", "maxSize": "70.16KB" }, + { "path": "./dist/clerk.browser.js", "maxSize": "70.2KB" }, { "path": "./dist/clerk.legacy.browser.js", "maxSize": "113KB" }, { "path": "./dist/clerk.headless*.js", "maxSize": "53.06KB" }, { "path": "./dist/ui-common*.js", "maxSize": "108.4KB" }, diff --git a/packages/clerk-js/src/core/resources/Session.ts b/packages/clerk-js/src/core/resources/Session.ts index 2abb36cc3e5..3308c9a9cb3 100644 --- a/packages/clerk-js/src/core/resources/Session.ts +++ b/packages/clerk-js/src/core/resources/Session.ts @@ -84,6 +84,12 @@ export class Session extends BaseResource implements SessionResource { return this._basePost({ action: 'touch', body: { active_organization_id: this.lastActiveOrganizationId }, + }).then(res => { + // touch() will potentially change the session state, and so we need to ensure we emit the updated token that comes back in the response. This avoids potential issues where the session cookie is out of sync with the current session state. + if (res.lastActiveToken) { + eventBus.emit(events.TokenUpdate, { token: res.lastActiveToken }); + } + return res; }); }; diff --git a/packages/clerk-js/src/core/resources/__tests__/Session.spec.ts b/packages/clerk-js/src/core/resources/__tests__/Session.spec.ts index 702432b5a19..80f7c0c4d2d 100644 --- a/packages/clerk-js/src/core/resources/__tests__/Session.spec.ts +++ b/packages/clerk-js/src/core/resources/__tests__/Session.spec.ts @@ -251,6 +251,46 @@ describe('Session', () => { }); }); + describe('touch()', () => { + let dispatchSpy: ReturnType; + + beforeEach(() => { + dispatchSpy = vi.spyOn(eventBus, 'emit'); + BaseResource.clerk = clerkMock() as any; + }); + + afterEach(() => { + dispatchSpy?.mockRestore(); + BaseResource.clerk = null as any; + }); + + it('dispatches token:update event on touch', async () => { + const mockToken = { object: 'token', jwt: mockJwt }; + const session = new Session({ + status: 'active', + id: 'session_1', + object: 'session', + user: createUser({}), + last_active_organization_id: null, + actor: null, + created_at: new Date().getTime(), + updated_at: new Date().getTime(), + last_active_token: mockToken, + } as SessionJSON); + + (BaseResource.clerk.getFapiClient().request as Mock).mockResolvedValue({ + payload: session, + }); + + await session.touch(); + + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith('token:update', { + token: session.lastActiveToken, + }); + }); + }); + describe('isAuthorized()', () => { it('user with permission to delete the organization should be able to delete the organization', async () => { const session = new Session({