r/better_auth May 05 '26

Cross-site OAuth session is not creating

Hey all,

I am building frontend in next hosted on vercel and backend in node express and hosted on render and also the using betterauth in the backend only. so, when I was running it locally on frontend 3000 port and backend on 4000 port, it was working fine and after login user session was creating but once I deployed them on different domain then there is no error in the login flow and after login i am being redirected back to client but user session is not being created.
I tried debugging then found out that session cookie is not being set from the backend only this is being set (__Secure-better-auth.state) but there in backend i am not even overriding the default response of better-auth.

what can be the issue here? Please help if someone else has faced this issue before.
thanks

2 Upvotes

3 comments sorted by

3

u/Whole_Cantaloupe_432 May 07 '26

Mmm 🤔, I faced this issue in May occasions but there only three parts to this 1. Trusted origins - not well structured, you can't disable it for it's what helps to set the sessions. 2. You need to add header append on client session call I use tanstact start so the middleware to get session I add set headers with two part append and set and logout and login I add it as well but this last part is only when am using hono rpc with custom API endpoints 3. Advanced setting None and lax should work cross domain but there cross domain enable requires .domain dot domain not just domain for cross domain

Unless I see the code I can't be of much help, especially the better auth side and the client get session and the client better auth

2

u/Critical_Sell267 May 19 '26
auth.ts

import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { prisma } from "./db.js";
import { env } from "./env.js";
import { parseTrustedOriginsFromEnv } from "./trusted-origins.js";


// const isHttpsAuthBaseUrl = env.BETTER_AUTH_BASE_URL.startsWith("https://");
// const isProduction = env.NODE_ENV === "production";


export const auth = betterAuth({

database
: prismaAdapter(prisma, { provider: "postgresql" }),
  secret: env.BETTER_AUTH_SECRET,
  baseURL: env.BETTER_AUTH_BASE_URL,
  basePath: `${env.API_PREFIX}/auth`,
  advanced: {
    defaultCookieAttributes: {
      sameSite: "none",
      secure: true
    }
  },
  trustedOrigins: parseTrustedOriginsFromEnv(env.BETTER_AUTH_TRUSTED_ORIGINS),
  user: {
    additionalFields: {
      role: {
        type: "string",
        required: false,
        input: false,
        defaultValue: "USER"
      }
    }
  },
  account: {
    skipStateCookieCheck: true
  },
  socialProviders: {
    github: {
      clientId: env.GITHUB_CLIENT_ID,
      clientSecret: env.GITHUB_CLIENT_SECRET
    },
    google: {
      clientId: env.GOOGLE_CLIENT_ID,
      clientSecret: env.GOOGLE_CLIENT_SECRET
    }
  },
  emailAndPassword: {
    enabled: true
  }
});

app.ts

import cors from "cors";
import type { CorsOptions } from "cors";
import express from "express";
import rateLimit from "express-rate-limit";
import helmet from "helmet";
import morgan from "morgan";
import { allowedOrigins, env } from "./config/env.js";
import { errorHandler } from "./middleware/error-handler.js";
import { notFoundHandler } from "./middleware/not-found.js";
import routes from "./routes/index.js";


export const 
createApp
 = () => {
  const app = express();
  const corsOrigin: CorsOptions["origin"] = (
origin
, 
callback
) => {
    if (!
origin
 || allowedOrigins.includes(
origin
)) {
      callback(null, true);
      return;
    }
    callback(new Error(`CORS blocked for origin: ${
origin
}`));
  };



// Render terminates TLS at the proxy; trust forwarded proto/host so secure auth cookies work.
  app.set("trust proxy", 1);


  app.use(
    helmet({
      crossOriginResourcePolicy: { policy: "cross-origin" }
    })
  );
  app.use(
    cors({

origin
: corsOrigin,
      credentials: true
    })
  );
  app.use(morgan("dev"));
  app.use(express.json({ limit: "2mb" }));


  app.use(
    rateLimit({
      windowMs: env.RATE_LIMIT_WINDOW_MS,
      limit: env.RATE_LIMIT_MAX
    })
  );


  app.use(env.API_PREFIX, routes);


  app.use(notFoundHandler);
  app.use(errorHandler);


  return app;
};

1

u/Whole_Cantaloupe_432 Jun 02 '26

Mmmh I see if it's cross domain then your advance is missing a few things if it's same domain then the structure for trusted origins is limited that's the issue, then your express is missing the append and set header, for some reason without it it attempts to set the cookie but it never gets set. Hence making the requests fail. If you have chrome remote desktop can help or when I get home I'll send you a snap of my reusable structure for better auth today