fix: revoke session on password reset

This commit is contained in:
KinfeMichael Tariku
2025-05-04 20:25:10 +03:00
committed by GitHub
parent 2baf504dc1
commit 3ddaa8a06f
3 changed files with 98 additions and 1 deletions

View File

@@ -142,3 +142,93 @@ describe("forget password", async (it) => {
expect(res2.error?.status).toBe(400);
});
});
describe("revoke sessions on password reset", async (it) => {
const mockSendEmail = vi.fn();
let token = "";
const { client, testUser, signInWithTestUser } = await getTestInstance(
{
emailAndPassword: {
enabled: true,
async sendResetPassword({ url }) {
token = url.split("?")[0].split("/").pop() || "";
await mockSendEmail();
},
revokeSessionsOnPasswordReset: true,
},
},
{
testWith: "sqlite",
},
);
it("should revoke other sessions when revokeSessionsOnPasswordReset is enabled", async () => {
const { headers } = await signInWithTestUser();
await client.forgetPassword({
email: testUser.email,
redirectTo: "http://localhost:3000",
});
await client.resetPassword(
{
newPassword: "new-password",
},
{
query: {
token,
},
},
);
const sessionAttempt = await client.getSession({
fetchOptions: {
headers,
},
});
expect(sessionAttempt.data).toBeNull();
});
it("should not revoke other sessions by default", async () => {
const { client, testUser, signInWithTestUser } = await getTestInstance(
{
emailAndPassword: {
enabled: true,
async sendResetPassword({ url }) {
token = url.split("?")[0].split("/").pop() || "";
await mockSendEmail();
},
},
},
{
testWith: "sqlite",
},
);
const { headers } = await signInWithTestUser();
await client.forgetPassword({
email: testUser.email,
redirectTo: "http://localhost:3000",
});
await client.resetPassword(
{
newPassword: "new-password",
},
{
query: {
token,
},
},
);
const sessionAttempt = await client.getSession({
fetchOptions: {
headers,
},
});
expect(sessionAttempt.data?.user).toBeDefined();
});
});

View File

@@ -285,7 +285,9 @@ export const resetPassword = createAuthEndpoint(
ctx,
);
await ctx.context.internalAdapter.deleteVerificationValue(verification.id);
if (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) {
await ctx.context.internalAdapter.deleteSessions(userId);
}
return ctx.json({
status: true,
});

View File

@@ -239,6 +239,11 @@ export type BetterAuthOptions = {
* Automatically sign in the user after sign up
*/
autoSignIn?: boolean;
/**
* Whether to revoke all other sessions when resetting password
* @default false
*/
revokeSessionsOnPasswordReset?: boolean;
};
/**
* list of social providers