Hono and Better-Auth

Do you think if I create my own route for better-auth, would it be double api calling? If I want to keep only one api.
47 Replies
Sithu Khant
Sithu KhantOP•3w ago
@lonelyplanet any tips? I see you created a new thread I think it is same concern as me 😄
lonelyplanet
lonelyplanet•3w ago
GitHub
GitHub - lonelyplanetdev/better-auth-with-hono-handler-nextjs
Contribute to lonelyplanetdev/better-auth-with-hono-handler-nextjs development by creating an account on GitHub.
lonelyplanet
lonelyplanet•3w ago
Thats an option to use the better-auth invokable functions without the using the auth handler in hono, Downside you would have to create your own routes for auth logic and couldnt use better-auth/client but you can use hono/client in that example @Sithu Khant That will allow you to manage one api but will make implementation more complex
Sithu Khant
Sithu KhantOP•3w ago
it won't work the better-auth live in /api/auth/*, if we mess up with its pass, auth server code will fail You need different path like /api/authorize/sign-in for your own one that is what I am doing it.
lonelyplanet
lonelyplanet•3w ago
You just dont add the handler
Sithu Khant
Sithu KhantOP•3w ago
the downside is I need any single routes like better-auth has that handler?
lonelyplanet
lonelyplanet•3w ago
Step 7
Sithu Khant
Sithu KhantOP•3w ago
it will still work?
lonelyplanet
lonelyplanet•3w ago
Have a look at that repo It works and uses hono+nextjs
Sithu Khant
Sithu KhantOP•3w ago
if it is true, I am hype!
lonelyplanet
lonelyplanet•3w ago
GitHub
better-auth-with-hono-handler-nextjs/src/app/api/[[...route]]/route...
Contribute to lonelyplanetdev/better-auth-with-hono-handler-nextjs development by creating an account on GitHub.
Sithu Khant
Sithu KhantOP•3w ago
let me try that...
lonelyplanet
lonelyplanet•3w ago
There is a small type error on the headers but its still working, the type error was safe to ignore since its just reading the headers
Sithu Khant
Sithu KhantOP•3w ago
what the f**k, it is working...!
lonelyplanet
lonelyplanet•3w ago
Wait i think the signout wont work... its because i messed up the headers
Sithu Khant
Sithu KhantOP•3w ago
I think the handler is only for frameworks
lonelyplanet
lonelyplanet•3w ago
The handler is there for the client but also means you dont have to manually write out all your auth apis
Sithu Khant
Sithu KhantOP•3w ago
I think if you have custom middleware, you might not need headers: c.req.header(), I have my own middleware
lonelyplanet
lonelyplanet•3w ago
but the concept is there you dont need the handler to use betterAuth.api
Sithu Khant
Sithu KhantOP•3w ago
Like this:
import { createMiddleware } from "hono/factory";

import { auth } from "../auth";

type Env = {
Variables: {
user: typeof auth.$Infer.Session.user | null;
session: typeof auth.$Infer.Session.session | null;
};
};

export const middleware = createMiddleware<Env>(async (c, next) => {
const session = await auth.api.getSession({ headers: c.req.raw.headers });

if (!session) {
return c.json({ message: "Unauthorized" });
}

c.set("user", session.user);
c.set("session", session.session);
return next();
});
import { createMiddleware } from "hono/factory";

import { auth } from "../auth";

type Env = {
Variables: {
user: typeof auth.$Infer.Session.user | null;
session: typeof auth.$Infer.Session.session | null;
};
};

export const middleware = createMiddleware<Env>(async (c, next) => {
const session = await auth.api.getSession({ headers: c.req.raw.headers });

if (!session) {
return c.json({ message: "Unauthorized" });
}

c.set("user", session.user);
c.set("session", session.session);
return next();
});
lonelyplanet
lonelyplanet•3w ago
That should work fine!, you still need to pass in headers to every betterAuth.api call
.post("/auth/signin", async (c) => {
const { email, password } = await c.req.json();
await auth.api.signInEmail({
headers: c.req.raw.headers,
body: {
email,
password,
},
});
return c.json({ success: true });
})
.post("/auth/signin", async (c) => {
const { email, password } = await c.req.json();
await auth.api.signInEmail({
headers: c.req.raw.headers,
body: {
email,
password,
},
});
return c.json({ success: true });
})
Sithu Khant
Sithu KhantOP•3w ago
thanks, I would try hey, how did you do for signout?
lonelyplanet
lonelyplanet•3w ago
use this as an example
Sithu Khant
Sithu KhantOP•3w ago
why I need raw headers?
lonelyplanet
lonelyplanet•3w ago
The functions require headers to get the current session without headers how would the signout method know to delete users a session and not users b session
Sithu Khant
Sithu KhantOP•3w ago
now, I can use like this on my client code:
async function onSubmit(data: typeof defaultValues) {
const { name, email, password } = data;
errorMessage = "";

const signInResponse = await makeClient(fetch).api.auth.signUp.$post({
json: { name, email, password }
});
const { message } = await signInResponse.json();

if (signInResponse.ok) {
successMessage = message;
goto("/subscriptions");
} else {
errorMessage = message;
}
async function onSubmit(data: typeof defaultValues) {
const { name, email, password } = data;
errorMessage = "";

const signInResponse = await makeClient(fetch).api.auth.signUp.$post({
json: { name, email, password }
});
const { message } = await signInResponse.json();

if (signInResponse.ok) {
successMessage = message;
goto("/subscriptions");
} else {
errorMessage = message;
}
I don't need both auth client and hono client anymore, I only would need hono client! That is cool!
lonelyplanet
lonelyplanet•3w ago
Auth client will not work this way anyway auth client needs the auth handler
Sithu Khant
Sithu KhantOP•3w ago
I mean it is not a problem to use both auth client and hono client if client and server are in the same folder, but might not be an ideal way if you have api from different server
lonelyplanet
lonelyplanet•3w ago
If you are deploying backend and frontend separately you can use a mono repo for type safety in development.
Sithu Khant
Sithu KhantOP•3w ago
really, how can I do that? like graphql? but I don't like that one maybe openapi?
lonelyplanet
lonelyplanet•3w ago
Turbo
Introduction | Turborepo
Welcome to the Turborepo documentation!
lonelyplanet
lonelyplanet•3w ago
You could have hono backend export the AppType and it can be used inside of the front end to create the honoClient with that exported type Turbo repo would be the easiest way to start playing with monorepos.
Sithu Khant
Sithu KhantOP•3w ago
thanks, I would try @lonelyplanet I think there is something wrong with my codes. the cookies didn't get store!!! this is my auth routes:
import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";

import { middleware } from "$lib/server/api/middleware";
import { auth } from "$lib/server/auth";

import { loginSchema, registerSchema } from "./schemas";

const app = new Hono()
.get("current", middleware, async (c) => {
const user = c.get("user");
const session = c.get("session");

return c.json({ user, session }, 200);
})
.post("signIn", zValidator("json", loginSchema), async (c) => {
const data = c.req.valid("json");
const { email, password } = data;

try {
const res = await auth.api.signInEmail({
header: c.req.raw.headers,
body: { email, password },
asResponse: true
});

console.log("signIn: ", await res.json());

return c.json({ message: `Success!` });
} catch (error) {
const message = error instanceof Error ? error.message : "Something went wrong!";
return c.json({ message }, 500);
}
})
.post("signUp", zValidator("json", registerSchema), async (c) => {
const data = c.req.valid("json");
const { name, email, password } = data;

try {
await auth.api.signUpEmail({
header: c.req.raw.headers,
body: { name, email, password },
asResponse: true
});

return c.json({ message: `Registration successful!` });
} catch (error) {
const message = error instanceof Error ? error.message : "Something went wrong!";
return c.json({ message }, 500);
}
})
.post("signOut", async (c) => {
try {
await auth.api.signOut({
headers: c.req.raw.headers
});

return c.json({ message: `Success!` });
} catch (error) {
const message = error instanceof Error ? error.message : "Something went wrong!";
return c.json({ message }, 500);
}
});

export default app;
import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";

import { middleware } from "$lib/server/api/middleware";
import { auth } from "$lib/server/auth";

import { loginSchema, registerSchema } from "./schemas";

const app = new Hono()
.get("current", middleware, async (c) => {
const user = c.get("user");
const session = c.get("session");

return c.json({ user, session }, 200);
})
.post("signIn", zValidator("json", loginSchema), async (c) => {
const data = c.req.valid("json");
const { email, password } = data;

try {
const res = await auth.api.signInEmail({
header: c.req.raw.headers,
body: { email, password },
asResponse: true
});

console.log("signIn: ", await res.json());

return c.json({ message: `Success!` });
} catch (error) {
const message = error instanceof Error ? error.message : "Something went wrong!";
return c.json({ message }, 500);
}
})
.post("signUp", zValidator("json", registerSchema), async (c) => {
const data = c.req.valid("json");
const { name, email, password } = data;

try {
await auth.api.signUpEmail({
header: c.req.raw.headers,
body: { name, email, password },
asResponse: true
});

return c.json({ message: `Registration successful!` });
} catch (error) {
const message = error instanceof Error ? error.message : "Something went wrong!";
return c.json({ message }, 500);
}
})
.post("signOut", async (c) => {
try {
await auth.api.signOut({
headers: c.req.raw.headers
});

return c.json({ message: `Success!` });
} catch (error) {
const message = error instanceof Error ? error.message : "Something went wrong!";
return c.json({ message }, 500);
}
});

export default app;
lonelyplanet
lonelyplanet•3w ago
The routes im doing since im in nextjs im using the nextjsCookies plugin in auth instance since your nolonger using the handler you need yo handle cookies yourself
Sithu Khant
Sithu KhantOP•3w ago
yep
Sithu Khant
Sithu KhantOP•3w ago
I think i need to follow this docs: https://www.better-auth.com/docs/concepts/cookies
Cookies | Better Auth
Learn how cookies are used in Better Auth.
Sithu Khant
Sithu KhantOP•3w ago
this is just my current auth server:
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";

import { db } from "../db";
import { account, session, user, verification } from "../db/schemas/auth-schema";

export const auth = betterAuth({
emailAndPassword: {
enabled: true
},
database: drizzleAdapter(db, {
provider: "sqlite",
schema: { user, session, account, verification }
})
});
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";

import { db } from "../db";
import { account, session, user, verification } from "../db/schemas/auth-schema";

export const auth = betterAuth({
emailAndPassword: {
enabled: true
},
database: drizzleAdapter(db, {
provider: "sqlite",
schema: { user, session, account, verification }
})
});
lonelyplanet
lonelyplanet•3w ago
use import { getCookie, getSignedCookie, setCookie, setSignedCookie, deleteCookie, } from 'hono/cookie' for your cookies setting and getting your shouldn't need to get a cookie since your passing all headers in on every request
Sithu Khant
Sithu KhantOP•3w ago
then? man!, I don't know too much about cookies!
lonelyplanet
lonelyplanet•3w ago
but for signup you want to first check if the const res = await auth.api.signUpEmail(..rest of code); then do const sessionToken = res.token; // this will be string | undefined this token is the value you will set the cookie I think i have a solution for you give me a second
Sithu Khant
Sithu KhantOP•3w ago
really...? thanks!
lonelyplanet
lonelyplanet•3w ago
https://github.com/better-auth/better-auth/issues/1470 Seems like there might be a bug atm
GitHub
The setSignedCookie type and import causes not TS errors and appear...
Is this suited for github? Yes, this is suited for github To Reproduce Import setSignedCookie from better auth into a file Try use it. Current vs. Expected behavior Should be a valid function as th...
Sithu Khant
Sithu KhantOP•3w ago
I got it working!!! I just need to set this:
const cookies = res.headers.get("set-cookie");
if (cookies) {
c.header("set-cookie", cookies);
}
const cookies = res.headers.get("set-cookie");
if (cookies) {
c.header("set-cookie", cookies);
}
like this:
.post("signIn", zValidator("json", loginSchema), async (c) => {
const data = c.req.valid("json");
const { email, password } = data;

try {
const res = await auth.api.signInEmail({
header: c.req.raw.headers,
body: { email, password },
asResponse: true
});

const cookies = res.headers.get("set-cookie");
if (cookies) {
c.header("set-cookie", cookies);
}

return c.json({ message: `Success!` });
} catch (error) {
const message = error instanceof Error ? error.message : "Something went wrong!";
return c.json({ message }, 500);
}
})
.post("signIn", zValidator("json", loginSchema), async (c) => {
const data = c.req.valid("json");
const { email, password } = data;

try {
const res = await auth.api.signInEmail({
header: c.req.raw.headers,
body: { email, password },
asResponse: true
});

const cookies = res.headers.get("set-cookie");
if (cookies) {
c.header("set-cookie", cookies);
}

return c.json({ message: `Success!` });
} catch (error) {
const message = error instanceof Error ? error.message : "Something went wrong!";
return c.json({ message }, 500);
}
})
chatgpt helped me.. xD!
lonelyplanet
lonelyplanet•3w ago
Does it work?
Sithu Khant
Sithu KhantOP•3w ago
yes... it is freaking working! The auth.ts file still the same
lonelyplanet
lonelyplanet•3w ago
Im sureprised glad it works
Sithu Khant
Sithu KhantOP•3w ago
thanks man

Did you find this page helpful?