fix: refresh secondary storage sessions on user update (#4522)

This commit is contained in:
Fraol Lemecha
2025-09-17 19:16:19 +03:00
committed by Bereket Engida
parent 809f82cb1e
commit ccc7c48dee
2 changed files with 94 additions and 0 deletions

View File

@@ -386,4 +386,63 @@ describe("Email Verification Secondary Storage", async () => {
expect(secondSignInSession.data?.user.email).toBe(sampleUser.email);
expect(secondSignInSession.data?.user.emailVerified).toBe(true);
});
it("should set emailVerified on all sessions", async () => {
const sampleUser = {
name: "sampler",
email: "sample@sample.com",
password: "samplesssss",
};
await client.signUp.email({
name: sampleUser.name,
email: sampleUser.email,
password: sampleUser.password,
});
const secondSignInHeaders = new Headers();
await client.signIn.email(
{
email: sampleUser.email,
password: sampleUser.password,
},
{
onSuccess: cookieSetter(secondSignInHeaders),
},
);
await auth.api.sendVerificationEmail({
body: {
email: sampleUser.email,
},
});
const headers = new Headers();
await client.verifyEmail({
query: {
token,
},
fetchOptions: {
onSuccess: cookieSetter(headers),
},
});
const session = await client.getSession({
fetchOptions: {
headers,
},
});
expect(session.data?.user.email).toBe(sampleUser.email);
expect(session.data?.user.emailVerified).toBe(true);
const secondSignInSession = await client.getSession({
fetchOptions: {
headers: secondSignInHeaders,
},
});
expect(secondSignInSession.data?.user.email).toBe(sampleUser.email);
expect(secondSignInSession.data?.user.emailVerified).toBe(true);
});
});

View File

@@ -77,6 +77,41 @@ export const createInternalAdapter = (
);
}
async function refreshUserSessions(user: User) {
if (!secondaryStorage) return;
const listRaw = await secondaryStorage.get(`active-sessions-${user.id}`);
if (!listRaw) return;
const now = Date.now();
const list =
safeJSONParse<{ token: string; expiresAt: number }[]>(listRaw) || [];
const validSessions = list.filter((s) => s.expiresAt > now);
await Promise.all(
validSessions.map(async ({ token }) => {
const cached = await secondaryStorage.get(token);
if (!cached) return;
const parsed = safeJSONParse<{ session: Session; user: User }>(cached);
if (!parsed) return;
const sessionTTL = Math.max(
Math.floor(new Date(parsed.session.expiresAt).getTime() - now) / 1000,
0,
);
await secondaryStorage.set(
token,
JSON.stringify({
session: parsed.session,
user,
}),
sessionTTL,
);
}),
);
}
return {
createOAuthUser: async (
user: Omit<User, "id" | "createdAt" | "updatedAt">,