mirror of
https://github.com/better-auth/better-auth.git
synced 2026-06-02 12:26:43 -05:00
fix: revoke session on password reset
This commit is contained in:
committed by
GitHub
parent
2baf504dc1
commit
3ddaa8a06f
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user