fix: prevent lastLoginMethod plugin from setting cookie on failed auth (#4673)

This commit is contained in:
KinfeMichael Tariku
2025-09-15 19:00:50 +03:00
committed by GitHub
parent 6373a1f0d5
commit e297caeb42
2 changed files with 58 additions and 12 deletions

View File

@@ -98,19 +98,26 @@ export const lastLoginMethod = <O extends LastLoginMethodOptions>(
handler: createAuthMiddleware(async (ctx) => {
const lastUsedLoginMethod = config.customResolveMethod(ctx);
if (lastUsedLoginMethod) {
// Inherit cookie attributes from Better Auth's centralized cookie system
// This ensures consistency with cross-origin, cross-subdomain, and security settings
const cookieAttributes = {
...ctx.context.authCookies.sessionToken.options,
maxAge: config.maxAge,
httpOnly: false, // Override: plugin cookies are not httpOnly
};
const setCookie = ctx.context.responseHeaders?.get("set-cookie");
const sessionTokenName =
ctx.context.authCookies.sessionToken.name;
const hasSessionToken =
setCookie && setCookie.includes(sessionTokenName);
if (hasSessionToken) {
// Inherit cookie attributes from Better Auth's centralized cookie system
// This ensures consistency with cross-origin, cross-subdomain, and security settings
const cookieAttributes = {
...ctx.context.authCookies.sessionToken.options,
maxAge: config.maxAge,
httpOnly: false, // Override: plugin cookies are not httpOnly
};
ctx.setCookie(
config.cookieName,
lastUsedLoginMethod,
cookieAttributes,
);
ctx.setCookie(
config.cookieName,
lastUsedLoginMethod,
cookieAttributes,
);
}
}
}),
},

View File

@@ -51,4 +51,43 @@ describe("lastLoginMethod", async () => {
});
expect(session?.user.lastLoginMethod).toBe("email");
});
it("should NOT set the last login method cookie on failed authentication", async () => {
const headers = new Headers();
const response = await client.signIn.email(
{
email: testUser.email,
password: "wrong-password",
},
{
onError(context) {
cookieSetter(headers)(context);
},
},
);
expect(response.error).toBeDefined();
const cookies = parseCookies(headers.get("cookie") || "");
expect(cookies.get("better-auth.last_used_login_method")).toBeUndefined();
});
it("should NOT set the last login method cookie on failed OAuth callback", async () => {
const headers = new Headers();
const response = await client.$fetch("/callback/google", {
method: "GET",
query: {
code: "invalid-code",
state: "invalid-state",
},
onError(context) {
cookieSetter(headers)(context);
},
});
expect(response.error).toBeDefined();
const cookies = parseCookies(headers.get("cookie") || "");
expect(cookies.get("better-auth.last_used_login_method")).toBeUndefined();
});
});