Skip to content

Commit

Permalink
fix(clerk-js): Clear session after deleting an account (#3628)
Browse files Browse the repository at this point in the history
Co-authored-by: panteliselef <[email protected]>
  • Loading branch information
octoper and panteliselef authored Jul 10, 2024
1 parent 3c42e55 commit 09f905a
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/chatty-feet-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@clerk/clerk-js": patch
---

Bug fix: Clear session cookie after a user deletes their account
2 changes: 1 addition & 1 deletion integration/testUtils/userProfilePageObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { common } from './commonPageObject';
export type EnchancedPage = ReturnType<typeof createAppPageObject>;
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;
Expand Down
47 changes: 47 additions & 0 deletions integration/tests/user-profile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
5 changes: 4 additions & 1 deletion packages/clerk-js/src/core/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -15,6 +15,7 @@ export const DeleteUserForm = withCardStateProvider((props: DeleteUserFormProps)
const { user } = useUser();
const { t } = useLocalizations();
const { otherSessions } = useMultipleSessions({ user });
const { setActive } = useClerk();

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

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: null,
beforeEmit: navigationCallback,
});
} catch (e) {
handleError(e, [], card.setError);
}
Expand Down

0 comments on commit 09f905a

Please sign in to comment.