fix(oauth): set account cookie on re-login when updateAccountOnSignIn is false (#7217)

This commit is contained in:
Taesu
2026-01-10 17:49:07 +09:00
committed by GitHub
parent fd020452bb
commit cd2ea4cd21
2 changed files with 133 additions and 23 deletions

View File

@@ -749,4 +749,109 @@ describe("account", async () => {
},
});
});
it("should set account cookie on re-login after sign-out when updateAccountOnSignIn is false", async () => {
const { auth, client, cookieSetter } = await getTestInstance({
socialProviders: {
google: {
clientId: "test",
clientSecret: "test",
enabled: true,
},
},
account: {
storeAccountCookie: true,
updateAccountOnSignIn: false, // important to test this scenario
},
});
const ctx = await auth.$context;
const accountDataCookieName = ctx.authCookies.accountData.name;
const headers = new Headers();
email = "re-login-test@test.com";
// first login with new user
const signInRes = await client.signIn.social({
provider: "google",
callbackURL: "/callback",
fetchOptions: {
onSuccess: cookieSetter(headers),
},
});
const state =
signInRes.data && "url" in signInRes.data && signInRes.data.url
? new URL(signInRes.data.url).searchParams.get("state") || ""
: "";
await client.$fetch("/callback/google", {
query: { state, code: "test" },
headers,
method: "GET",
onError(context) {
expect(context.response.status).toBe(302);
cookieSetter(headers)({ response: context.response });
},
});
// verify account cookie is set after first login
const firstLoginAccessToken = await client.getAccessToken(
{ providerId: "google" },
{ headers },
);
expect(firstLoginAccessToken.error).toBeFalsy();
expect(firstLoginAccessToken.data?.accessToken).toBe("test");
// sign out
await client.signOut({ fetchOptions: { headers } });
// clear headers to simulate fresh session
const newHeaders = new Headers();
// re-login with same OAuth account
const reLoginRes = await client.signIn.social({
provider: "google",
callbackURL: "/callback",
fetchOptions: {
onSuccess: cookieSetter(newHeaders),
},
});
const reLoginState =
reLoginRes.data && "url" in reLoginRes.data && reLoginRes.data.url
? new URL(reLoginRes.data.url).searchParams.get("state") || ""
: "";
let accountCookieSetOnReLogin = false;
await client.$fetch("/callback/google", {
query: { state: reLoginState, code: "test" },
headers: newHeaders,
method: "GET",
onError(context) {
expect(context.response.status).toBe(302);
// check if account_data cookie is set on re-login
const cookies = parseSetCookieHeader(
context.response.headers.get("set-cookie") || "",
);
const accountDataCookie = cookies.get(accountDataCookieName);
accountCookieSetOnReLogin = !!accountDataCookie?.value;
cookieSetter(newHeaders)({ response: context.response });
},
});
// verify account cookie is set on re-login
expect(accountCookieSetOnReLogin).toBe(true);
// verify getAccessToken works after re-login
const reLoginAccessToken = await client.getAccessToken(
{ providerId: "google" },
{ headers: newHeaders },
);
expect(reLoginAccessToken.error).toBeFalsy();
expect(reLoginAccessToken.data?.accessToken).toBe("test");
});
});

View File

@@ -93,30 +93,35 @@ export async function handleOAuthUserInfo(
});
}
} else {
if (c.context.options.account?.updateAccountOnSignIn !== false) {
const updateData = Object.fromEntries(
Object.entries({
idToken: account.idToken,
accessToken: await setTokenUtil(account.accessToken, c.context),
refreshToken: await setTokenUtil(account.refreshToken, c.context),
accessTokenExpiresAt: account.accessTokenExpiresAt,
refreshTokenExpiresAt: account.refreshTokenExpiresAt,
scope: account.scope,
}).filter(([_, value]) => value !== undefined),
);
if (c.context.options.account?.storeAccountCookie) {
await setAccountCookie(c, {
...account,
...updateData,
});
}
const freshTokens =
c.context.options.account?.updateAccountOnSignIn !== false
? Object.fromEntries(
Object.entries({
idToken: account.idToken,
accessToken: await setTokenUtil(account.accessToken, c.context),
refreshToken: await setTokenUtil(
account.refreshToken,
c.context,
),
accessTokenExpiresAt: account.accessTokenExpiresAt,
refreshTokenExpiresAt: account.refreshTokenExpiresAt,
scope: account.scope,
}).filter(([_, value]) => value !== undefined),
)
: {};
if (Object.keys(updateData).length > 0) {
await c.context.internalAdapter.updateAccount(
hasBeenLinked.id,
updateData,
);
}
if (c.context.options.account?.storeAccountCookie) {
await setAccountCookie(c, {
...hasBeenLinked,
...freshTokens,
});
}
if (Object.keys(freshTokens).length > 0) {
await c.context.internalAdapter.updateAccount(
hasBeenLinked.id,
freshTokens,
);
}
if (