Skip to content

Commit 09f905a

Browse files
fix(clerk-js): Clear session after deleting an account (clerk#3628)
Co-authored-by: panteliselef <panteliselef@outlook.com>
1 parent 3c42e55 commit 09f905a

5 files changed

Lines changed: 65 additions & 8 deletions

File tree

.changeset/chatty-feet-battle.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+
Bug fix: Clear session cookie after a user deletes their account

integration/testUtils/userProfilePageObject.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { common } from './commonPageObject';
66
export type EnchancedPage = ReturnType<typeof createAppPageObject>;
77
export type TestArgs = { page: EnchancedPage; context: BrowserContext; browser: Browser };
88

9-
export type Sections = 'profile' | 'emailAddresses' | 'username' | 'phoneNumbers';
9+
export type Sections = 'profile' | 'emailAddresses' | 'username' | 'phoneNumbers' | 'danger';
1010

1111
export const createUserProfileComponentPageObject = (testArgs: TestArgs) => {
1212
const { page } = testArgs;

integration/tests/user-profile.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,4 +264,51 @@ export default function Page() {
264264
state: 'visible',
265265
});
266266
});
267+
268+
test('can delete account', async ({ page, context }) => {
269+
const m = createTestUtils({ app });
270+
const delFakeUser = m.services.users.createFakeUser({
271+
withUsername: true,
272+
fictionalEmail: true,
273+
withPhoneNumber: true,
274+
});
275+
await m.services.users.createBapiUser({
276+
...delFakeUser,
277+
username: undefined,
278+
phoneNumber: undefined,
279+
});
280+
281+
const u = createTestUtils({ app, page, context });
282+
await u.po.signIn.goTo();
283+
await u.po.signIn.waitForMounted();
284+
await u.po.signIn.signInWithEmailAndInstantPassword({ email: delFakeUser.email, password: delFakeUser.password });
285+
await u.po.expect.toBeSignedIn();
286+
287+
await u.po.userProfile.goTo();
288+
await u.po.userProfile.waitForMounted();
289+
await u.po.userProfile.switchToSecurityTab();
290+
291+
await u.page
292+
.getByRole('button', {
293+
name: /delete account/i,
294+
})
295+
.click();
296+
297+
await u.page.locator('input[name=deleteConfirmation]').fill('Delete account');
298+
299+
await u.page
300+
.getByRole('button', {
301+
name: /delete account/i,
302+
})
303+
.click();
304+
305+
await u.po.expect.toBeSignedOut();
306+
307+
await u.page.waitForAppUrl('/');
308+
309+
// Make sure that the session cookie is deleted
310+
const sessionCookieList = (await u.page.context().cookies()).filter(cookie => cookie.name === '__session');
311+
312+
expect(sessionCookieList.length).toBe(0);
313+
});
267314
});

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,10 @@ export class Clerk implements ClerkInterface {
732732
}
733733

734734
// getToken syncs __session and __client_uat to cookies using events.TokenUpdate dispatched event.
735-
await newSession?.getToken();
735+
const token = await newSession?.getToken();
736+
if (!token) {
737+
eventBus.dispatch(events.TokenUpdate, { token: null });
738+
}
736739

737740
//2. If there's a beforeEmit, typically we're navigating. Emit the session as
738741
// undefined, then wait for beforeEmit to complete before emitting the new session.

packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useUser } from '@clerk/shared/react';
1+
import { useClerk, useUser } from '@clerk/shared/react';
22

33
import { useSignOutContext } from '../../contexts';
44
import { Col, localizationKeys, Text, useLocalizations } from '../../customizables';
@@ -15,6 +15,7 @@ export const DeleteUserForm = withCardStateProvider((props: DeleteUserFormProps)
1515
const { user } = useUser();
1616
const { t } = useLocalizations();
1717
const { otherSessions } = useMultipleSessions({ user });
18+
const { setActive } = useClerk();
1819

1920
const confirmationField = useFormControl('deleteConfirmation', '', {
2021
type: 'text',
@@ -38,12 +39,13 @@ export const DeleteUserForm = withCardStateProvider((props: DeleteUserFormProps)
3839
}
3940

4041
await user.delete();
41-
4242
// TODO: Investigate if we need to call `setActive` with {session: null}
43-
if (otherSessions.length === 0) {
44-
return navigateAfterSignOut();
45-
}
46-
await navigateAfterMultiSessionSingleSignOutUrl();
43+
const navigationCallback =
44+
otherSessions.length === 0 ? navigateAfterSignOut : navigateAfterMultiSessionSingleSignOutUrl;
45+
return await setActive({
46+
session: null,
47+
beforeEmit: navigationCallback,
48+
});
4749
} catch (e) {
4850
handleError(e, [], card.setError);
4951
}

0 commit comments

Comments
 (0)