mirror of
https://github.com/better-auth/better-auth.git
synced 2026-05-25 00:22:43 -05:00
fix(oauth): set account cookie on re-login when updateAccountOnSignIn is false (#7217)
This commit is contained in:
@@ -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");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 (
|
||||
|
||||
Reference in New Issue
Block a user