BA
Better Auth•2w ago
aswnss

Next Hono session is empty

I do not know how to structure this question to be honest, But is there a way to get the session details or another way to check if the user is logged in ? if the frontend and backend is hosted on seperate server ( ie: auth.ts file is not available at next frontend side). in the image: 1. backend is the hono application 2. users is the frontend nextjs application What works: Login is working , register user is working What i need get the session details of the logged in user. Some template projects i saw in github uses hono as a replacement to next api route. That is not what i want . I want the hono to be a seperate server.
No description
No description
Solution:
So to digest the issue was I was logging in from a server component which did not set the cookies in the nextjs application. which would not be a problem if I was using hono as a replacement of the next api router, where nextCookies() plugin could be helping while the logging was happening from a server component. but in my case i am not replacing the next router .. i am having a seperate hono server so i guess the plugin nextCookies would not reflect to the next server ...
No description
Jump to solution
23 Replies
Shaki
Shaki•2w ago
Did you add the nextjs setCookie plugin? https://www.better-auth.com/docs/integrations/next and also specify which domains should have access to the cookie https://www.better-auth.com/docs/concepts/cookies#cross-subdomain-cookies
Next.js integration | Better Auth
Integrate Better Auth with Next.js.
Cookies | Better Auth
Learn how cookies are used in Better Auth.
aswnss
aswnssOP•2w ago
well technically yes , this file is inside the hono project
No description
aswnss
aswnssOP•2w ago
i am using this authclient from nextjs front end to call the signin method
import { createAuthClient } from "better-auth/client";

export const authClient = createAuthClient({
baseURL: "http://localhost:5000/api/auth",
});
import { createAuthClient } from "better-auth/client";

export const authClient = createAuthClient({
baseURL: "http://localhost:5000/api/auth",
});
handlelogin function from frontend
const handleLogin = async (formData: FormData) => {
"use server"
const [ email, password ] = [ formData.get('email'), formData.get('password') ]
if (email === null || password === null) {
console.log("Please fill all the fields")
return
}
const { data, error } = await authClient.signIn.email({
email: email as string,
password: password as string,
}, {
onSuccess: (ctx) => {
console.log(ctx)
redirect('/profile')
}
})

}
const handleLogin = async (formData: FormData) => {
"use server"
const [ email, password ] = [ formData.get('email'), formData.get('password') ]
if (email === null || password === null) {
console.log("Please fill all the fields")
return
}
const { data, error } = await authClient.signIn.email({
email: email as string,
password: password as string,
}, {
onSuccess: (ctx) => {
console.log(ctx)
redirect('/profile')
}
})

}
No description
Shaki
Shaki•2w ago
add the advanced option to your auth config and replace the domain/trustedOrigins with your client url
export const auth = betterAuth({
advanced: {
crossSubDomainCookies: {
enabled: true,
domain: ".example.com", // Domain with a leading period
},
defaultCookieAttributes: {
secure: true,
httpOnly: true,
sameSite: "none", // Allows CORS-based cookie sharing across subdomains
partitioned: true, // New browser standards will mandate this for foreign cookies
},
},
trustedOrigins: [
'https://example.com',
'https://app1.example.com',
'https://app2.example.com',
],
})
export const auth = betterAuth({
advanced: {
crossSubDomainCookies: {
enabled: true,
domain: ".example.com", // Domain with a leading period
},
defaultCookieAttributes: {
secure: true,
httpOnly: true,
sameSite: "none", // Allows CORS-based cookie sharing across subdomains
partitioned: true, // New browser standards will mandate this for foreign cookies
},
},
trustedOrigins: [
'https://example.com',
'https://app1.example.com',
'https://app2.example.com',
],
})
aswnss
aswnssOP•2w ago
hi updated
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { nextCookies } from "better-auth/next-js";
import prisma from "../../prisma/client";

export const auth = betterAuth({
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
advanced: {
crossSubDomainCookies: {
enabled: true,
domains: ["localhost"],
},
defaultCookieAttributes: {
secure: true,
httpOnly: true,
sameSite: "none", // Allows CORS-based cookie sharing across subdomains
partitioned: true, // New browser standards will mandate this for foreign cookies
},
},
emailAndPassword: {
enabled: true,
},
trustedOrigins: ["http://localhost:3000"],
plugins: [nextCookies()],
});

export type AuthType = {
Variables: {
user: typeof auth.$Infer.Session.user | null;
session: typeof auth.$Infer.Session.session | null;
};
};
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { nextCookies } from "better-auth/next-js";
import prisma from "../../prisma/client";

export const auth = betterAuth({
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
advanced: {
crossSubDomainCookies: {
enabled: true,
domains: ["localhost"],
},
defaultCookieAttributes: {
secure: true,
httpOnly: true,
sameSite: "none", // Allows CORS-based cookie sharing across subdomains
partitioned: true, // New browser standards will mandate this for foreign cookies
},
},
emailAndPassword: {
enabled: true,
},
trustedOrigins: ["http://localhost:3000"],
plugins: [nextCookies()],
});

export type AuthType = {
Variables: {
user: typeof auth.$Infer.Session.user | null;
session: typeof auth.$Infer.Session.session | null;
};
};
still the session is null , this is how i getsession in my frontend right now
import { authClient } from "@/lib/auth-client";
import { headers } from "next/headers";
export default async function ProfilePage() {
const session = authClient.getSession({
fetchOptions: {
headers: await headers()
}
})
return (
<div>
{JSON.stringify(session)}
</div>
);
}
import { authClient } from "@/lib/auth-client";
import { headers } from "next/headers";
export default async function ProfilePage() {
const session = authClient.getSession({
fetchOptions: {
headers: await headers()
}
})
return (
<div>
{JSON.stringify(session)}
</div>
);
}
this is the authclient
import { createAuthClient } from "better-auth/client";

export const authClient = createAuthClient({
baseURL: "http://localhost:5000/api/auth",
});
import { createAuthClient } from "better-auth/client";

export const authClient = createAuthClient({
baseURL: "http://localhost:5000/api/auth",
});
Shaki
Shaki•2w ago
try awaiting the authClient in the frontend
import { authClient } from "@/lib/auth-client";
import { headers } from "next/headers";
export default async function ProfilePage() {
const session = await authClient.getSession({
fetchOptions: {
headers: await headers()
}
})
return (
<div>
{JSON.stringify(session)}
</div>
);
}
import { authClient } from "@/lib/auth-client";
import { headers } from "next/headers";
export default async function ProfilePage() {
const session = await authClient.getSession({
fetchOptions: {
headers: await headers()
}
})
return (
<div>
{JSON.stringify(session)}
</div>
);
}
and try updating auth config
crossSubDomainCookies: {
enabled: true,
domains: ["localhost:3000"],
},
crossSubDomainCookies: {
enabled: true,
domains: ["localhost:3000"],
},
aswnss
aswnssOP•2w ago
that actually did make a change previously the session was an empty object {} now its {data:null,error:null}
No description
Shaki
Shaki•2w ago
Okay cool. Can you try logging in again?
aswnss
aswnssOP•2w ago
well i did but not good , this ss is taken in a incognito window ... I will try by creating a new user
No description
aswnss
aswnssOP•2w ago
nop new user also returns data null and error null
Shaki
Shaki•2w ago
Ok. My only other guess will be trying this. I see the server is returning a success but for whatever reason next isn't reading the cookie
const session = await authClient.getSession({)
const session = await authClient.getSession({)
aswnss
aswnssOP•2w ago
funny thing is registration and login is actually working .. just cant get the session 😿
Shaki
Shaki•2w ago
Does your fetch have credentials include on the client?
import { hc } from "hono/client";
import type { AppType } from "./server"; // Your Hono app type

const client = hc<AppType>("http://localhost:8787/", {
fetch: ((input, init) => {
return fetch(input, {
...init,
credentials: "include" // Required for sending cookies cross-origin
});
}) satisfies typeof fetch,
});

// Now your client requests will include credentials
const response = await client.someProtectedEndpoint.$get();
import { hc } from "hono/client";
import type { AppType } from "./server"; // Your Hono app type

const client = hc<AppType>("http://localhost:8787/", {
fetch: ((input, init) => {
return fetch(input, {
...init,
credentials: "include" // Required for sending cookies cross-origin
});
}) satisfies typeof fetch,
});

// Now your client requests will include credentials
const response = await client.someProtectedEndpoint.$get();
aswnss
aswnssOP•2w ago
tried and failed, well i thought of that way too like since i am logging in using server action that happens on the server side and then next cant set the cookies since the auth.ts file is actually on a seperate project ( nextCookies() ) might not be working. So I tried making the login request from a client component but that gave me the issue like you need to have Access-Control-Cross-Credentials set to true , but could not debug that issue ..
sebastian
sebastian•2w ago
show your cors settings @aswnss and as you said you should not use nextcookies in sepearte backend auth instance
aswnss
aswnssOP•2w ago
this is the issue ... this type of architecture is used when we switch the next api with hono right .. that is not what i am trying to achieve .. in my mind i need to detach the frontend ... not just the frontend api routing
No description
aswnss
aswnssOP•2w ago
cors is set like this in hono
import { Hono } from "hono";
import { etag } from "hono/etag";
import { logger } from "hono/logger";
import { cors } from "hono/cors";
import { prettyJSON } from "hono/pretty-json";

import auth from "@/routes/auth";
import { AuthType } from "@/lib/auth";

const app = new Hono<{ Bindings: AuthType }>({
strict: false,
});

app.use("*", etag(), logger());
app.use(
"*",
cors({
origin: ["http://localhost:3000"],
})
);
app.use("*", prettyJSON());

const routes = [auth] as const;

routes.forEach((route) => {
app.basePath("/api").route("/", route);
});

app.get("/", (c) => {
return c.json(
{
data: {},
message: "Welcome to Hono Backend",
},
200
);
});

app.notFound((c) => {
return c.json({
data: {},
message: "Endpoint not found",
});
});

export default app;
import { Hono } from "hono";
import { etag } from "hono/etag";
import { logger } from "hono/logger";
import { cors } from "hono/cors";
import { prettyJSON } from "hono/pretty-json";

import auth from "@/routes/auth";
import { AuthType } from "@/lib/auth";

const app = new Hono<{ Bindings: AuthType }>({
strict: false,
});

app.use("*", etag(), logger());
app.use(
"*",
cors({
origin: ["http://localhost:3000"],
})
);
app.use("*", prettyJSON());

const routes = [auth] as const;

routes.forEach((route) => {
app.basePath("/api").route("/", route);
});

app.get("/", (c) => {
return c.json(
{
data: {},
message: "Welcome to Hono Backend",
},
200
);
});

app.notFound((c) => {
return c.json({
data: {},
message: "Endpoint not found",
});
});

export default app;
aswnss
aswnssOP•2w ago
No description
sebastian
sebastian•2w ago
add those
allowHeaders: ["Content-Type", "Authorization"],
allowMethods: ["POST", "GET", "OPTIONS"],
exposeHeaders: ["Content-Length"],
maxAge: 600,
credentials: true,
allowHeaders: ["Content-Type", "Authorization"],
allowMethods: ["POST", "GET", "OPTIONS"],
exposeHeaders: ["Content-Length"],
maxAge: 600,
credentials: true,
aswnss
aswnssOP•2w ago
did not solve the issue 😥 .. well let me try logging in from a client component now instead of the "use server" method
sebastian
sebastian•2w ago
have you tried in incognito what does the dev tools says also when you are fetching on the server you shouldnt probably use the authclient and when fetching in client use the authClient with credentials: "include" also in the server you should use credentials include this is very important read the official integration guide carefully: https://www.better-auth.com/docs/integrations/hono
aswnss
aswnssOP•2w ago
this did fix it
{"data":{"session":{"expiresAt":"2025-05-22T14:24:50.913Z","token":"m2DfpinGF4hjbf2Xac9bpDeGdcSYI8h0","createdAt":"2025-05-15T14:24:50.914Z","updatedAt":"2025-05-15T14:24:50.914Z","ipAddress":"","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0","userId":"KTsu89oAeW4PHhQ6aXJ32pjkRVPDfEKx","id":"7PPsj7pDyt5u6v2DrO9hUMdnNVFlSeh9"},"user":{"name":"Aswin Lal M","email":"[email protected]","emailVerified":false,"image":null,"createdAt":"2025-05-15T06:33:04.825Z","updatedAt":"2025-05-15T06:33:04.825Z","id":"KTsu89oAeW4PHhQ6aXJ32pjkRVPDfEKx"}},"error":null}
{"data":{"session":{"expiresAt":"2025-05-22T14:24:50.913Z","token":"m2DfpinGF4hjbf2Xac9bpDeGdcSYI8h0","createdAt":"2025-05-15T14:24:50.914Z","updatedAt":"2025-05-15T14:24:50.914Z","ipAddress":"","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0","userId":"KTsu89oAeW4PHhQ6aXJ32pjkRVPDfEKx","id":"7PPsj7pDyt5u6v2DrO9hUMdnNVFlSeh9"},"user":{"name":"Aswin Lal M","email":"[email protected]","emailVerified":false,"image":null,"createdAt":"2025-05-15T06:33:04.825Z","updatedAt":"2025-05-15T06:33:04.825Z","id":"KTsu89oAeW4PHhQ6aXJ32pjkRVPDfEKx"}},"error":null}
Solution
aswnss
aswnss•2w ago
So to digest the issue was I was logging in from a server component which did not set the cookies in the nextjs application. which would not be a problem if I was using hono as a replacement of the next api router, where nextCookies() plugin could be helping while the logging was happening from a server component. but in my case i am not replacing the next router .. i am having a seperate hono server so i guess the plugin nextCookies would not reflect to the next server What fixed : when i made the login request from a client component nextjs will automatically set the cookies when the header contains a set cookie value Why it did not work previously: The cors setting was needed to be added in the hono side which i did not do
No description

Did you find this page helpful?