CRITICAL BUG IN PRODUCTION: authClient.useSession returns the session of a random user

I used authClient.useSession in the development environment, everything is working perfectly fine. When I tried to use it in production, it gets the session of a random user all of the time even if I log out & sign in again, it gets that random user. I "solved" this issue by getting the session on the server for now....
10 Replies
Ping
Ping3w ago
Are you able to consistently get this issue? Are you able to create a repro?
Maqed
MaqedOP3w ago
auth.ts:
import { betterAuth } from "better-auth";
import { admin } from "better-auth/plugins";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { headers } from "next/headers";
import { db } from "./db";
import { env } from "@/env";

export const auth = betterAuth({
database: prismaAdapter(db, {
provider: "postgresql",
}),
emailAndPassword: {
enabled: true,
autoSignIn: true,
minPasswordLength: 8,
sendResetPassword: async ({ user, url, token }, request) => {
// TODO: implement reset password email send
console.log({
user,
url,
token,
});
},
},
socialProviders: {
google: {
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
},
facebook: {
clientId: env.FACEBOOK_CLIENT_ID,
clientSecret: env.FACEBOOK_CLIENT_SECRET,
},
},
advanced: {
database: { useNumberId: true },
},
plugins: [admin()],
});

export const getServerAuthSession = async () =>
await auth.api.getSession({
headers: await headers(),
});
import { betterAuth } from "better-auth";
import { admin } from "better-auth/plugins";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { headers } from "next/headers";
import { db } from "./db";
import { env } from "@/env";

export const auth = betterAuth({
database: prismaAdapter(db, {
provider: "postgresql",
}),
emailAndPassword: {
enabled: true,
autoSignIn: true,
minPasswordLength: 8,
sendResetPassword: async ({ user, url, token }, request) => {
// TODO: implement reset password email send
console.log({
user,
url,
token,
});
},
},
socialProviders: {
google: {
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
},
facebook: {
clientId: env.FACEBOOK_CLIENT_ID,
clientSecret: env.FACEBOOK_CLIENT_SECRET,
},
},
advanced: {
database: { useNumberId: true },
},
plugins: [admin()],
});

export const getServerAuthSession = async () =>
await auth.api.getSession({
headers: await headers(),
});
auth-client.ts:
import { createAuthClient } from "better-auth/react";
import { adminClient } from "better-auth/client/plugins";

export const authClient = createAuthClient({
plugins: [adminClient()],
});
import { createAuthClient } from "better-auth/react";
import { adminClient } from "better-auth/client/plugins";

export const authClient = createAuthClient({
plugins: [adminClient()],
});
logout-dialog.tsx (where the bug occurs)
"use client";
import { Button } from "@/components/ui/button";
import { useRouter } from "next/navigation";
import Image from "next/image";
import {
Dialog,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { useTransition } from "react";

import { authClient } from "@/lib/auth-client";

export function LogoutDialog() {
const { data: session } = authClient.useSession();
const router = useRouter();
const [isPending, startTransition] = useTransition();

const logout = async () => {
startTransition(async () => {
await authClient.signOut({
fetchOptions: {
onSuccess: () => {
router.push("/auth");
},
},
});
});
};
if (!session) return null;
return (
<Dialog>
<DialogTrigger asChild>
<Button
variant="ghost"
className="font-crete-round normal-case text-xs"
disabled={isPending}
>
<Image src="/images/auth/log-out.svg" width={16} height={16} alt="" />
Log out
</Button>
</DialogTrigger>
<DialogContent className="bg-gradient-to-t from-[#A7ABB4] to-[#F4F4F4]">
<DialogHeader>
<DialogTitle className="font-crete-round text-sm text-black font-normal">
Log Out of "{session.user.name}" acount?
</DialogTitle>
</DialogHeader>
<DialogFooter className="flex justify-center items-center flex-row">
<DialogClose className="w-[45%]" size="lg" disabled={isPending} />
<Button
size="lg"
variant="destructive"
onClick={logout}
disabled={isPending}
>
{isPending ? "Logging out..." : "Log out"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
"use client";
import { Button } from "@/components/ui/button";
import { useRouter } from "next/navigation";
import Image from "next/image";
import {
Dialog,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { useTransition } from "react";

import { authClient } from "@/lib/auth-client";

export function LogoutDialog() {
const { data: session } = authClient.useSession();
const router = useRouter();
const [isPending, startTransition] = useTransition();

const logout = async () => {
startTransition(async () => {
await authClient.signOut({
fetchOptions: {
onSuccess: () => {
router.push("/auth");
},
},
});
});
};
if (!session) return null;
return (
<Dialog>
<DialogTrigger asChild>
<Button
variant="ghost"
className="font-crete-round normal-case text-xs"
disabled={isPending}
>
<Image src="/images/auth/log-out.svg" width={16} height={16} alt="" />
Log out
</Button>
</DialogTrigger>
<DialogContent className="bg-gradient-to-t from-[#A7ABB4] to-[#F4F4F4]">
<DialogHeader>
<DialogTitle className="font-crete-round text-sm text-black font-normal">
Log Out of "{session.user.name}" acount?
</DialogTitle>
</DialogHeader>
<DialogFooter className="flex justify-center items-center flex-row">
<DialogClose className="w-[45%]" size="lg" disabled={isPending} />
<Button
size="lg"
variant="destructive"
onClick={logout}
disabled={isPending}
>
{isPending ? "Logging out..." : "Log out"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
When I use this component, the session it gets is another user's session. I tried checking networking & the problem comes from /api/auth/get-session endpoint where the session of the other user (Not the current) is shown
bekacru
bekacru3w ago
what version are you in? also is there anyway you can send us something we can reproduce on our end?
Maqed
MaqedOP3w ago
I'm in version 1.2.7 What's the other way? Could you please tell me how you can reproduce other than having the auth instance & the client? The problem happened when a new user signed up (with google credentials), the data from /api/auth/get-session becomes the data of that user. The problem happens ONLY when using authClient.useSession(), when I tried getting the session from the server (i.e: auth.api.getSession()), it got fixed. I tried to log out/log in again from my account but still the returned value is the session of the last signed up user
Ping
Ping3w ago
Reproduce as in a temporary repo implementing the issue you're encountering so that we can debug further
bekacru
bekacru3w ago
We couldn't reproduce the issue in our end, with the same setup. It'd be easier for us to look at, if you can give us a minimal repo we can take a look to see the issue happening.
Maqed
MaqedOP3w ago
Sure I'll do that ASAP. could you please try signing in with an account. Then in other browser try signing up with google credentials account (the bug happened twice this way, when 2 users signed up with google)
KZ
KZ3w ago
@Maqed production was deployed to vercel?
Maqed
MaqedOP3w ago
Netlify
KZ
KZ3w ago
wondering if you were logging like via sentry or analytics any session (not just better-auth) details in the hosting runtime. i remember vercel had a hot bug that was related to nextjs header issues but that was a while ago and you're not use vercel i would verify that by cramming in a debug session id initiated from the client side and then see if you randomly get the issue if its the same session back when its happening is it consisten?

Did you find this page helpful?