From cd333758c7d51cfa852b6896c76696d4272ebab3 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Thu, 27 Jun 2024 23:04:31 +0300 Subject: [PATCH 1/7] fix(clerk-js): Clear session after deleting account --- .../components/UserProfile/DeleteUserForm.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx b/packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx index 37515f17f2f..21561b8ab7d 100644 --- a/packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx +++ b/packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx @@ -1,4 +1,4 @@ -import { useUser } from '@clerk/shared/react'; +import { useClerk, useUser } from '@clerk/shared/react'; import { useSignOutContext } from '../../contexts'; import { Col, localizationKeys, Text, useLocalizations } from '../../customizables'; @@ -15,6 +15,7 @@ export const DeleteUserForm = withCardStateProvider((props: DeleteUserFormProps) const { user } = useUser(); const { t } = useLocalizations(); const { otherSessions } = useMultipleSessions({ user }); + const { setActive, client } = useClerk(); const confirmationField = useFormControl('deleteConfirmation', '', { type: 'text', @@ -37,13 +38,17 @@ export const DeleteUserForm = withCardStateProvider((props: DeleteUserFormProps) throw Error('user is not defined'); } + // Store the session so it can be ended after the user is deleted + const session = client.lastActiveSessionId; await user.delete(); - // TODO: Investigate if we need to call `setActive` with {session: null} - if (otherSessions.length === 0) { - return navigateAfterSignOut(); - } - await navigateAfterMultiSessionSingleSignOutUrl(); + const navigationCallback = otherSessions.length === 0 + ? navigateAfterSignOut + : navigateAfterMultiSessionSingleSignOutUrl; + return await setActive({ + session, + beforeEmit: navigateAfterSignOut, + }); } catch (e) { handleError(e, [], card.setError); } From 57273e54ee0c858071fcc5e212afd6e34c18f994 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Thu, 27 Jun 2024 23:06:19 +0300 Subject: [PATCH 2/7] chore(repo): Add Changeset --- .changeset/chatty-feet-battle.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/chatty-feet-battle.md diff --git a/.changeset/chatty-feet-battle.md b/.changeset/chatty-feet-battle.md new file mode 100644 index 00000000000..12b1ebb325c --- /dev/null +++ b/.changeset/chatty-feet-battle.md @@ -0,0 +1,5 @@ +--- +"@clerk/clerk-js": patch +--- + +Fix bug where session cookie wasn't cleared after account deletion From e4d71aad4a800d7e167fcf81bb10383d1d830ac6 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Thu, 27 Jun 2024 23:18:31 +0300 Subject: [PATCH 3/7] fix(clerk-js): Dispatch a token update if not there is no session available --- packages/clerk-js/src/core/clerk.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index cf047327ca0..5ba17d7ee3c 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -732,7 +732,10 @@ export class Clerk implements ClerkInterface { } // getToken syncs __session and __client_uat to cookies using events.TokenUpdate dispatched event. - await newSession?.getToken(); + const token = await newSession?.getToken(); + if (!token) { + eventBus.dispatch(events.TokenUpdate, { token: null }); + } //2. If there's a beforeEmit, typically we're navigating. Emit the session as // undefined, then wait for beforeEmit to complete before emitting the new session. From e3f6686df5a3a8715d2460716dd8938981d4f579 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Fri, 28 Jun 2024 18:54:39 +0300 Subject: [PATCH 4/7] fix(clerk-js): Pass the correct callback to beforeEmit --- .../src/ui/components/UserProfile/DeleteUserForm.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx b/packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx index 21561b8ab7d..6513a83a4b4 100644 --- a/packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx +++ b/packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx @@ -42,12 +42,11 @@ export const DeleteUserForm = withCardStateProvider((props: DeleteUserFormProps) const session = client.lastActiveSessionId; await user.delete(); // TODO: Investigate if we need to call `setActive` with {session: null} - const navigationCallback = otherSessions.length === 0 - ? navigateAfterSignOut - : navigateAfterMultiSessionSingleSignOutUrl; + const navigationCallback = + otherSessions.length === 0 ? navigateAfterSignOut : navigateAfterMultiSessionSingleSignOutUrl; return await setActive({ session, - beforeEmit: navigateAfterSignOut, + beforeEmit: navigationCallback, }); } catch (e) { handleError(e, [], card.setError); From a5bea3196df8591befd80426ad68cb7e3401ed81 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Mon, 1 Jul 2024 18:33:54 +0300 Subject: [PATCH 5/7] fix(clerk-js): Set active session to null --- .../src/ui/components/UserProfile/DeleteUserForm.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx b/packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx index 6513a83a4b4..d50246bc5e9 100644 --- a/packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx +++ b/packages/clerk-js/src/ui/components/UserProfile/DeleteUserForm.tsx @@ -15,7 +15,7 @@ export const DeleteUserForm = withCardStateProvider((props: DeleteUserFormProps) const { user } = useUser(); const { t } = useLocalizations(); const { otherSessions } = useMultipleSessions({ user }); - const { setActive, client } = useClerk(); + const { setActive } = useClerk(); const confirmationField = useFormControl('deleteConfirmation', '', { type: 'text', @@ -38,14 +38,12 @@ export const DeleteUserForm = withCardStateProvider((props: DeleteUserFormProps) throw Error('user is not defined'); } - // Store the session so it can be ended after the user is deleted - const session = client.lastActiveSessionId; await user.delete(); // TODO: Investigate if we need to call `setActive` with {session: null} const navigationCallback = otherSessions.length === 0 ? navigateAfterSignOut : navigateAfterMultiSessionSingleSignOutUrl; return await setActive({ - session, + session: null, beforeEmit: navigationCallback, }); } catch (e) { From f2937fbf4b6383f68a0a3180bd7cb161a266746b Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Mon, 1 Jul 2024 21:38:06 +0300 Subject: [PATCH 6/7] feat(e2e): Add integration test for account deletion --- .../testUtils/userProfilePageObject.ts | 2 +- integration/tests/user-profile.test.ts | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/integration/testUtils/userProfilePageObject.ts b/integration/testUtils/userProfilePageObject.ts index 05ecb7f9195..bf8473ed4af 100644 --- a/integration/testUtils/userProfilePageObject.ts +++ b/integration/testUtils/userProfilePageObject.ts @@ -6,7 +6,7 @@ import { common } from './commonPageObject'; export type EnchancedPage = ReturnType; export type TestArgs = { page: EnchancedPage; context: BrowserContext; browser: Browser }; -export type Sections = 'profile' | 'emailAddresses' | 'username' | 'phoneNumbers'; +export type Sections = 'profile' | 'emailAddresses' | 'username' | 'phoneNumbers' | 'danger'; export const createUserProfileComponentPageObject = (testArgs: TestArgs) => { const { page } = testArgs; diff --git a/integration/tests/user-profile.test.ts b/integration/tests/user-profile.test.ts index 9f1cfbc685e..d79375879d2 100644 --- a/integration/tests/user-profile.test.ts +++ b/integration/tests/user-profile.test.ts @@ -264,4 +264,51 @@ export default function Page() { state: 'visible', }); }); + + test('can delete account', async ({ page, context }) => { + const m = createTestUtils({ app }); + const delFakeUser = m.services.users.createFakeUser({ + withUsername: true, + fictionalEmail: true, + withPhoneNumber: true, + }); + await m.services.users.createBapiUser({ + ...delFakeUser, + username: undefined, + phoneNumber: undefined, + }); + + const u = createTestUtils({ app, page, context }); + await u.po.signIn.goTo(); + await u.po.signIn.waitForMounted(); + await u.po.signIn.signInWithEmailAndInstantPassword({ email: delFakeUser.email, password: delFakeUser.password }); + await u.po.expect.toBeSignedIn(); + + await u.po.userProfile.goTo(); + await u.po.userProfile.waitForMounted(); + await u.po.userProfile.switchToSecurityTab(); + + await u.page + .getByRole('button', { + name: /delete account/i, + }) + .click(); + + await u.page.locator('input[name=deleteConfirmation]').fill('Delete account'); + + await u.page + .getByRole('button', { + name: /delete account/i, + }) + .click(); + + await u.po.expect.toBeSignedOut(); + + await u.page.waitForAppUrl('/'); + + // Make sure that the session cookie is deleted + const sessionCookieList = (await u.page.context().cookies()).filter(cookie => cookie.name === '__session'); + + expect(sessionCookieList.length).toBe(0); + }); }); From 08f0d420544756fcd02cddc8980fe0b8ba5b55ed Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Mon, 1 Jul 2024 21:47:09 +0300 Subject: [PATCH 7/7] Update .changeset/chatty-feet-battle.md Co-authored-by: panteliselef --- .changeset/chatty-feet-battle.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/chatty-feet-battle.md b/.changeset/chatty-feet-battle.md index 12b1ebb325c..f91696d5072 100644 --- a/.changeset/chatty-feet-battle.md +++ b/.changeset/chatty-feet-battle.md @@ -2,4 +2,4 @@ "@clerk/clerk-js": patch --- -Fix bug where session cookie wasn't cleared after account deletion +Bug fix: Clear session cookie after a user deletes their account