Session cookie not working in production deployment
Hello everyone,
Unfortunately, my authentication only works on localhost and not in production or the deployed development environment.
We have multiple frontends. Central authentication runs via an Express API (api-ts.playin.gg).
The test frontend for authentication is auth.playin.gg.
Signing in via Google works; you are redirected to /protected and the cookie is set, but the frontend apparently can't retrieve the sessions. What could be the reason for this?
Can anyone help me here? I'm also open to any suggestions for improvement π
auth.ts (Express API)
Frontend (auth.playin.gg/protected, NextJS)

81 Replies
you mean session is returning null ?
like can you check up on the cookie exists with the headers
Yes, if I log the headers, the cookie is present
OUTPUT:
HEADERS __Secure-playingg_gguardian.session_token=xxx; ...
SESSION null
can you do the fetching with the internal api like this
No, unfortunately not. I've separated the frontend and backend. The internal API is therefore in the Express API.
I only have the client in NextJS. This prevents access to the internal API.
Fetching with the headers or useSession worked on localhost.
Oh if u r using express Ig you should be fine
Can you manually pass the cookie to headers options itself
Hmm, you mean read the specific cookie and then pass it in the fetchoptions as headers: { cookie: ... }
I don't know if this is intended, and it's also a bit cumbersome. I don't really understand what's wrong with it π
I also didn't really find any documentation deployment specific
can u pls share the root page and initialization of your experess app ?
Sure
EXPRESS src/index.ts
EXPRESS src/auth.ts
I created a route in the Express API as a test. Authentication with the cookie set trough the frontend sign in works. It seems that the problem is only in the frontend in NextJS, where the cookie isn't recognized via the useSession or getSession hook, even though it exists in the await headers.
What is your nextjs version ?
Running latest packages
"next": "15.3.0",
"react": "^19.1.0",
Also passkeys are not working in production for me, localhost works fine π«

if you have crosssubdomain cookie setup remove
defaultCookieAttributes
I tried it. Unfortunately, it doesn't change the existing problems with retrieving the session or passkey sign in
after the user authenticated on auth.playing.gg where do they get redirected to?
At the moment, I'm using auth.playin.gg as a pure development environment. It redirects you to /protected, which works, both on localhost and deployed. But in "production" it redirects you back to /auth/login, because it doesn't recognize the session, as described above. Headers are present.
We will have several frontends later, as well as an Expo App
could you check if the cookie is being properly set in the browser and if it's sent with the request in the middleware?
We actually don't use auth middleware. And we would like to migrate from Next-Auth.
Since only a few pages are fully protected, we would query and redirect the session accordingly in the layouts/pages. Or we would only check whether the user is logged in when certain features are clicked.
So far, we've done this with Next-Auth's useSession/getServerSideSession.
But it would be the same process as implemented above on the ProtectedSSRPage.
As far as I understand, the cookies are definitely present, but not recognized by useSession / getSession on the authClient. I only have the client, since the auth.ts is on Express.
Here I had logged the cookies
just to be sure remove the cookie prefix as well and on prod inforce
useSecureCookies
by setting it to true
in the configHmm, I tried that. It's also deployed in auth.playin.gg. But it still doesn't work. I don't understand it somehow
faced the same problem
in production
it sets the cookie in browser after login but after redirect, it clear the the cookie in browser which redirect back to login page
i found the problem is in middleware because it uses fetch
this is the error i get in console
i got this error when i run in prod in local machine
i have a backend in expressjs and nextjs as frontend
@bekacru have any solution
i have detected is problem is useSecureCookie in prod
i deployed in aws with nginix it doesn't work
Hmm, I'm also using NGINX as a reverse proxy. I was wondering if that could be the problem, but according to the logs, the cookies are present on the backend. I've already played around with the configuration a bit, but so far, I've never had any problems with cookies... but the better-auth session hooks in my deployed frontend still don't want to recognize the session, even though the cookie is present π¦ I still haven't found a solution.
Same issue, the cookie is set when sign-in but get-session call remove it
It's actually not even removed for me. I still have the cookie, but it's just not recognized.
the response of get-session call, why return 3 null cookies?

what is your baseURL or
BETTER_AUTH_URL
set to?
it's trying to unset cookiesyes, the request does send a valid cookie. I suspect the issue might be related to the session database schema
is this on prod or local?
prod
what is your base url set to?
my API runs on a subdomain, api.osler, while my Next.js app runs on the base domain
import { betterAuth } from 'better-auth';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import * as schema from '@/db/schema';
import { db } from '@/db'; import { env } from '@/env'; export const auth = betterAuth({ secret: env.BETTER_AUTH_SECRET, baseUrl: env.BETTER_AUTH_URL, database: drizzleAdapter(db, { provider: 'pg', schema: schema, }), user: { modelName: 'doctor', }, account: { fields: { userId: 'doctorId', } }, session: { fields: { userId: 'doctorId', }, storeSessionInDatabase: true, }, emailAndPassword: { enabled: true, async sendResetPassword(data, request) { console.log(data, request); }, }, advanced: { crossSubDomainCookies: { enabled: true, domain: '.osler.app', }, useSecureCookies: true, }, appName: 'Osler', trustedOrigins: ['http://localhost:3001', 'https://osler.app'], socialProviders: { google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, } } });
import { db } from '@/db'; import { env } from '@/env'; export const auth = betterAuth({ secret: env.BETTER_AUTH_SECRET, baseUrl: env.BETTER_AUTH_URL, database: drizzleAdapter(db, { provider: 'pg', schema: schema, }), user: { modelName: 'doctor', }, account: { fields: { userId: 'doctorId', } }, session: { fields: { userId: 'doctorId', }, storeSessionInDatabase: true, }, emailAndPassword: { enabled: true, async sendResetPassword(data, request) { console.log(data, request); }, }, advanced: { crossSubDomainCookies: { enabled: true, domain: '.osler.app', }, useSecureCookies: true, }, appName: 'Osler', trustedOrigins: ['http://localhost:3001', 'https://osler.app'], socialProviders: { google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, } } });
first
baseUrl
should be baseURL
oh π³
I miss type safety right now
will be added on the next release. Extra values aren't being validated by ts cause of generics π«‘
Mine is BETTER_AUTH_URL=https://api-ts.playin.gg
Frontend: https://auth.playin.gg
But @Fall don't seem to have exact the same problem
PlayinGG | Authentication
PlayinGG Auth Service
if you're not incase enforcing
useSecureCookies
on prod do that
when it's behind reverse proxy, it may not enable it by defaultI had already tried this on your suggestion, unfortunately it didn't change anything
so the issue is after sign in and properly seting cookies
getSession
returns null, right?The cookie clearing during the get-session call continues, and the baseURL mismatch wasnβt the problem. Itβs the same issue as @daanish
yes
Yeah, exactly. The cookie is set correctly for me, but getSession and useSession only return null in PROD. On localhost, everything works perfectly. After signing in, you're redirected to /protected, but then, of course, you're redirected directly back to signin because the session is null.

same after redirect cookie is being cleared
just to make sure, are you all in the latest version of the library?
i'm using: "better-auth": "^1.2.5",
im using 1.2.2
Express Backend
"better-auth": "^1.2.6",
NextJS Frontend
"better-auth": "^1.2.6",
"next": "15.3.0",
"react": "^19.1.0",
Upgraded this morning hoping it would fix something, no change
no change same problem after upgrade
this is my prod url you would check it https://roro-ai.com/auth/login
Welcome to client
Generated by create-nx-workspace
I have summarized my code and the problem here:
https://devlix.notion.site/Session-returns-null-in-production-1d40d00e2286802e9f60fa8e9b77d699?pvs=4
Felix on Notion
Session returns null in production | Notion
This scenario works on localhost. However, it doesn't work on the deployment https://auth.playin.gg (Backend: https://api-ts.playin.gg).
looking into it. will report back
curios, have you tried not making a call from next server environment and just directly from the client to your auth server?
Mmm, you mean from my localhost to the prod API? The cookie is set on .playin.gg, so that wouldn't work.
problem is because of useSessionCookie at prod
is true
no from your prod client/frontend to your prod api
in the notion doc, it looks like your making a call from a server component
do you mean
useSecureCookies
?yes
is it working now?
no i tried in local developement with useSecureCookie to true but i doesn't work
in local host secure cookie doesn't work
secure cookies only work under https protocol
yes, its just clears the cookie after login to redirect.this prod link https://roro-ai.com/auth/login
Welcome to client
Generated by create-nx-workspace
Ahh, I see, so it doesn't work on both the server and client side with getSession/useSession. I have a /protected-client page where the session is also null in prod. I added it in Notion.
in your client code
session is initally always null so this will always redirect regardless. You need to check if
session.isPending
is also false
Makes sense, thanks. It actually works client-side now, thanks π It's strange that I've never encountered this issue with localhost before. I'm still having the same issue server-side, though.
One more note: I'm also using the same backend with the Expo plugin. The session works there. It's probably a slightly different architecture, though.
can you check on the server if it returns both error and data null?
for me problem is solved
i added crossSubDomain
HEADERS _ga=GA1.1.1653196102.1744302730; _ga_X5724CWZ7F=GS1.1.1744552980.4.1.1744556733.0.0.0; __Secure-playingg.session_token=xxx
SESSION DATA null
SESSION ERROR { status: 0, statusText: '' }
@daanish like this?
advanced: {
crossSubDomainCookies: {
enabled: true,
domain: '.osler.app',
},
useSecureCookies: true,
}
yes
my frontend is roro-ai.com and backend is at backend.roro-ai.com
but it created four cookie in browser client
same, my frontend is osler.app and backend is api.osler.app
but the problem continue here
in prod or localhost
just prod
localhost works fine
is it https enabled
yes
did you try auth.api.getSession()
Unfortunately I don't have access to the internal API because I don't use NextJS as a backend, but only as a frontend. My backend is on express
ok but you are using async in page.tsx
try using async in layout.tsx and pass it as props to child
don't use in page.tsx and try it
NEXTJS_NO_ASYNC_PAGE
Ensures that the exported Next.js page component and its transitive dependencies are not asynchronous, as that blocks the rendering of the page.
also you are using header as await header() but from nextjs 15 header are async to use header try this fetchOptions: (await header())
Hmm, I see your point about centrally fetching the session async in the layout. However, I also do a lot of fetching on the individual pages server-side, which is why I need async there anyway. Your suggestion is best practice, but it doesn't change my problem that the session is null.
It doesn't really matter which call I make from the authclient, whether it's retrieving sessions, accounts, etc. everything that is serverside doesn't work with nextjs π¦
fetchOptions: (await header()) => This doesn't work.
Do you remove async in page.tsx
I am facing similar issue with oauth , i am using google as social provider , getting getsession is null after login using google ,but session data successfully saved in database , email and password works fine , only problem with google ,
@bekacru any update on this issue
Unfortunately not. To this day, I'm still facing the same problem: the session can only be accessed client-side. I still haven't had any success with NextJS on the server-side π¦
How are you using it on server side for getting the session
Here is my summarized code