I have BE written in Hono, that is providing auth using better-auth and Expo app that consumes it (I am using ios in development, not Expo Go). I m working with cookie-based auth that is proposed by better-auth. Email + password auth works just as expected, the response contains cookie in header that I save using CookieManager, but when I try to access cookie header from Google signIn, then its always empty.
Why is the response from google signIn without the cookie header?
I am not sure if the problem might come from TrustedOrigins, CORS or with callback URL from Google. Or is this supposed to work like this and I need to fetch for user information after he signs using Google ?
(The signIn from Google pops the popup as expected and if I click the account it seems to work fine, but doesnt contain the cookie header, I dont know why)
Client code
export const authClient = createAuthClient({
baseURL: API_BASE_URL,
plugins: [
expoClient({
scheme: "shop",
storagePrefix: "shop_auth_",
storage: SectureStore,
}),
],
});
const loginWithGoogle = async () => {
await authClient.signIn.social(
{
provider: "google",
callbackURL: "/",
},
{
onSuccess: () => {
setIsLoggedIn(true);
router.replace("/(tabs)");
},
}
);
};
BE code
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
schema: {
user,
account,
session,
verification,
},
}),
emailAndPassword: {
enabled: true,
requireEmailVerification: true,
},
socialProviders: {
google: {
enabled: true,
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
prompt: "select_account",
},
},
plugins: [openAPI(), expo()],
secret: process.env.BETTER_AUTH_SECRET,
trustedOrigins: [process.env.TRUSTED_ORIGIN as string],
});
I fixed it this way.
You cant get the header from social callback url, so you need to check your hono authClient if it has cookie (the cookie is set after the successful social signIn). Then I take the cookie from authClient and save it using CookieManager from "@react-native-cookies/cookies"
const loginWithGoogle = useCallback(async () => {
await authClient.signIn.social(
{
provider: "google",
callbackURL: "/",
},
{
onSuccess: async () => {},
}
);
//Cant get cookie directly from social Auth, because the cookie header is not set
// we need to get it from the authClient
//The returned cookie string starts with ; - thats why we remove it
const cookieString = authClient.getCookie()?.split(";")[1];
await setCookieFromHeader(API_BASE_URL as string, cookieString);
if (cookieString) {
setIsLoggedIn(true);
router.replace("/(tabs)");
}
}, [router]);
export async function setCookieFromHeader(
apiBaseUrl: string,
setCookieHeader: string
) {
if (!setCookieHeader) return;
const [nameValue] = setCookieHeader.split(";");
const [name, value] = nameValue.split("=");
await CookieManager.set(apiBaseUrl, {
name: name.trim(),
value: value.trim(),
domain: new URL(apiBaseUrl).hostname,
path: "/",
});
}