Skip to content

Commit b0e47f1

Browse files
authored
fix(clerk-js): Preserve active organization when attempting to switch to personal workspace (#6103)
1 parent b23d4ae commit b0e47f1

File tree

3 files changed

+96
-5
lines changed

3 files changed

+96
-5
lines changed

.changeset/dark-cougars-burn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
---
4+
5+
Maintain current active organization when `setActive({ organization: null })` is called with force organization selection enabled

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

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,87 @@ describe('Clerk singleton', () => {
537537
});
538538
});
539539
});
540+
541+
describe('with force organization selection enabled', () => {
542+
const mockSession = {
543+
id: '1',
544+
remove: jest.fn(),
545+
status: 'active',
546+
user: {},
547+
touch: jest.fn(() => Promise.resolve()),
548+
getToken: jest.fn(),
549+
lastActiveToken: { getRawString: () => 'mocked-token' },
550+
};
551+
552+
beforeEach(() => {
553+
mockEnvironmentFetch.mockReturnValue(
554+
Promise.resolve({
555+
userSettings: mockUserSettings,
556+
displayConfig: mockDisplayConfig,
557+
isSingleSession: () => false,
558+
isProduction: () => false,
559+
isDevelopmentOrStaging: () => true,
560+
organizationSettings: {
561+
forceOrganizationSelection: true,
562+
},
563+
}),
564+
);
565+
});
566+
567+
afterEach(() => {
568+
mockSession.remove.mockReset();
569+
mockSession.touch.mockReset();
570+
mockEnvironmentFetch.mockReset();
571+
572+
// cleanup global window pollution
573+
(window as any).__unstable__onBeforeSetActive = null;
574+
(window as any).__unstable__onAfterSetActive = null;
575+
});
576+
577+
it('does not update session to personal workspace', async () => {
578+
const mockSessionWithOrganization = {
579+
id: '1',
580+
status: 'active',
581+
user: {
582+
organizationMemberships: [
583+
{
584+
id: 'orgmem_id',
585+
organization: {
586+
id: 'org_id',
587+
slug: 'some-org-slug',
588+
},
589+
},
590+
],
591+
},
592+
touch: jest.fn(),
593+
getToken: jest.fn(),
594+
};
595+
596+
mockClientFetch.mockReturnValue(Promise.resolve({ signedInSessions: [mockSessionWithOrganization] }));
597+
const sut = new Clerk(productionPublishableKey);
598+
await sut.load();
599+
600+
mockSessionWithOrganization.touch.mockImplementationOnce(() => {
601+
sut.session = mockSessionWithOrganization as any;
602+
return Promise.resolve();
603+
});
604+
mockSessionWithOrganization.getToken.mockImplementation(() => 'mocked-token');
605+
606+
await sut.setActive({ organization: 'some-org-slug' });
607+
608+
await waitFor(() => {
609+
expect(mockSessionWithOrganization.touch).toHaveBeenCalled();
610+
expect(mockSessionWithOrganization.getToken).toHaveBeenCalled();
611+
expect((mockSessionWithOrganization as any as ActiveSessionResource)?.lastActiveOrganizationId).toEqual(
612+
'org_id',
613+
);
614+
expect(sut.session).toMatchObject(mockSessionWithOrganization);
615+
});
616+
617+
await sut.setActive({ organization: null });
618+
expect(sut.session).toMatchObject(mockSessionWithOrganization);
619+
});
620+
});
540621
});
541622

542623
describe('.load()', () => {

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,10 +1071,6 @@ export class Clerk implements ClerkInterface {
10711071
);
10721072
}
10731073

1074-
if (organization === null && this.environment?.organizationSettings?.forceOrganizationSelection) {
1075-
throw new Error('setActive requires an organization parameter when organization selection is forced.');
1076-
}
1077-
10781074
const onBeforeSetActive: SetActiveHook =
10791075
typeof window !== 'undefined' && typeof window.__unstable__onBeforeSetActive === 'function'
10801076
? window.__unstable__onBeforeSetActive
@@ -1107,7 +1103,16 @@ export class Clerk implements ClerkInterface {
11071103
const matchingOrganization = newSession.user.organizationMemberships.find(
11081104
mem => mem.organization.slug === organizationIdOrSlug,
11091105
);
1110-
newSession.lastActiveOrganizationId = matchingOrganization?.organization.id || null;
1106+
1107+
const newLastActiveOrganizationId = matchingOrganization?.organization.id || null;
1108+
const isPersonalWorkspace = newLastActiveOrganizationId === null;
1109+
1110+
// Do not update in-memory to personal workspace if force organization selection is enabled
1111+
if (this.environment?.organizationSettings?.forceOrganizationSelection && isPersonalWorkspace) {
1112+
return;
1113+
}
1114+
1115+
newSession.lastActiveOrganizationId = newLastActiveOrganizationId;
11111116
}
11121117
}
11131118

0 commit comments

Comments
 (0)