docs: rewrite Hono integration guide (#10763)

This commit is contained in:
Taesu
2026-08-12 18:25:44 +00:00
committed by GitHub
parent be47e9418b
commit c35c41ef2a
+140 -139
View File
@@ -3,185 +3,186 @@ title: Hono Integration
description: Integrate Better Auth with Hono.
---
Before you start, make sure you have a Better Auth instance configured. If you haven't done that yet, check out the [installation](/docs/installation).
Both Hono and Better Auth use the Web Standard `Request` and `Response` APIs, so you can mount Better Auth directly in a Hono application without an adapter.
### Mount the handler
Before you begin, make sure you have a Better Auth instance configured. If not, follow the [installation guide](/docs/installation).
We need to mount the handler to Hono endpoint.
## Setup
```ts
### Create a Hono App
If you are starting a new project, create a Hono application and select the template for your runtime or platform:
```package-install
npx create-hono@latest
```
If you already have a Hono application, you can skip this step. See the [create-hono documentation](https://hono.dev/docs/guides/create-hono) for available templates and options, or Hono's [Getting Started guides](https://hono.dev/docs/getting-started/basic) for runtime-specific setup and deployment.
### Mount the Auth Handler
Add the highlighted route to your existing Hono application:
```ts title="src/index.ts"
import { Hono } from "hono";
import { auth } from "./auth";
import { serve } from "@hono/node-server";
const app = new Hono();
app.on(["POST", "GET"], "/api/auth/*", (c) => {
return auth.handler(c.req.raw);
});
app.all("/api/auth/*", (c) => auth.handler(c.req.raw)); // [!code highlight]
serve(app);
export default app;
```
### Cors
That's all you need to connect Better Auth to Hono!
To configure cors, you need to use the `cors` plugin from `hono/cors`.
If you're using another runtime, keep your existing entry point and add the same `app.all()` route.
```ts
`app.all()` forwards every HTTP method to Better Auth using the raw Web Standard `Request` from `c.req.raw`. Better Auth validates the method and returns a `Response` that Hono sends directly. Register the auth route before any catch-all route that could handle the request first.
<Callout type="info">
The resulting Hono route must match your Better Auth `basePath`, which
defaults to `/api/auth`. If your app already uses `new
Hono().basePath("/api")`, mount Better Auth at `/auth/*`:
```ts
const app = new Hono().basePath("/api");
app.all("/auth/*", (c) => auth.handler(c.req.raw));
```
</Callout>
### Additional Configuration
#### Cloudflare Workers
Better Auth uses `AsyncLocalStorage`. Add the [`nodejs_compat` compatibility flag](https://developers.cloudflare.com/workers/configuration/compatibility-flags/#nodejs-compatibility-flag) to your Wrangler configuration:
```jsonc title="wrangler.jsonc"
{
// Use "nodejs_als" instead if you only need AsyncLocalStorage.
"compatibility_flags": ["nodejs_compat"],
}
```
## CORS
To allow cross-origin authentication requests, register Hono's [CORS middleware](https://hono.dev/docs/middleware/builtin/cors) before the Better Auth route:
```ts title="src/index.ts"
import { Hono } from "hono";
import { cors } from "hono/cors"; // [!code highlight]
import { auth } from "./auth";
import { serve } from "@hono/node-server";
import { cors } from "hono/cors";
const app = new Hono();
app.use(
"/api/auth/*", // or replace with "*" to enable cors for all routes
cors({
origin: "http://localhost:3001", // replace with your origin
allowHeaders: ["Content-Type", "Authorization"],
allowMethods: ["POST", "GET", "OPTIONS"],
exposeHeaders: ["Content-Length"],
maxAge: 600,
credentials: true,
}),
);
app.use( // [!code highlight]
"/api/auth/*", // [!code highlight]
cors({ // [!code highlight]
origin: "http://localhost:3001", // [!code highlight]
credentials: true, // [!code highlight]
}), // [!code highlight]
); // [!code highlight]
app.on(["POST", "GET"], "/api/auth/*", (c) => {
return auth.handler(c.req.raw);
});
app.all("/api/auth/*", (c) => auth.handler(c.req.raw));
serve(app);
export default app;
```
> **Important:** CORS middleware must be registered before your routes. This ensures that cross-origin requests are properly handled before they reach your authentication endpoints.
Add the same origin to Better Auth's `trustedOrigins` configuration:
### Middleware
```ts title="auth.ts"
import { betterAuth } from "better-auth";
You can add a middleware to save the `session` and `user` in a `context` and also add validations for every route.
export const auth = betterAuth({
trustedOrigins: ["http://localhost:3001"], // [!code highlight]
});
```
```ts
import { Hono } from "hono";
When `credentials` is enabled, configure an explicit CORS origin instead of `*` and add the same origin to Better Auth's `trustedOrigins`. See [Cookies](/docs/concepts/cookies) for cross-domain and cross-subdomain cookie behavior.
## Middleware
You can also use custom middleware to make the current session available through Hono's context:
```ts title="src/session-middleware.ts"
import { createMiddleware } from "hono/factory";
import { auth } from "./auth";
import { serve } from "@hono/node-server";
import { cors } from "hono/cors";
const app = new Hono<{
type Env = {
Variables: {
user: typeof auth.$Infer.Session.user | null;
session: typeof auth.$Infer.Session.session | null
}
}>();
session: typeof auth.$Infer.Session | null;
};
};
app.use("*", async (c, next) => {
const session = await auth.api.getSession({ headers: c.req.raw.headers });
if (!session) {
c.set("user", null);
c.set("session", null);
await next();
return;
}
c.set("user", session.user);
c.set("session", session.session);
await next();
});
app.on(["POST", "GET"], "/api/auth/*", (c) => {
return auth.handler(c.req.raw);
});
serve(app);
```
This will allow you to access the `user` and `session` object in all of your routes.
```ts
app.get("/session", (c) => {
const session = c.get("session")
const user = c.get("user")
if(!user) return c.body(null, 401);
return c.json({
session,
user
export const sessionMiddleware = createMiddleware<Env>(async (c, next) => {
const session = await auth.api.getSession({
headers: c.req.raw.headers,
});
c.set("session", session);
await next();
});
```
### Cross-Domain Cookies
Add the middleware to any route that needs access to the current session:
By default, all Better Auth cookies are set with `SameSite=Lax`. If you need to use cookies across different domains, you’ll need to set `SameSite=None` and `Secure=true`. However, we recommend using subdomains whenever possible, as this allows you to keep `SameSite=Lax`. To enable cross-subdomain cookies, simply turn on `crossSubDomainCookies` in your auth config.
```ts title="src/index.ts"
import { Hono } from "hono";
import { HTTPException } from "hono/http-exception";
import { sessionMiddleware } from "./session-middleware";
```ts title="auth.ts"
export const auth = createAuth({
advanced: {
crossSubDomainCookies: {
enabled: true
}
}
})
```
const app = new Hono();
If you still need to set `SameSite=None` and `Secure=true`, you can adjust these attributes globally through `cookieOptions` in the `createAuth` configuration.
app.get("/hello", sessionMiddleware, (c) => {
const session = c.get("session");
```ts title="auth.ts"
export const auth = createAuth({
advanced: {
defaultCookieAttributes: {
sameSite: "none",
secure: true,
partitioned: true // New browser standards will mandate this for foreign cookies
}
}
})
```
if (!session) {
throw new HTTPException(401);
}
You can also customize cookie attributes individually by setting them within `cookies` in your auth config.
```ts title="auth.ts"
export const auth = createAuth({
advanced: {
cookies: {
sessionToken: {
attributes: {
sameSite: "none",
secure: true,
partitioned: true // New browser standards will mandate this for foreign cookies
}
}
}
}
})
```
### Client-Side Configuration
When using the Hono client (`@hono/client`) to make requests to your Better Auth-protected endpoints, you need to configure it to send credentials (cookies) with cross-origin requests.
```ts title="api.ts"
import { hc } from "hono/client";
import type { AppType } from "./server"; // Your Hono app type
const client = hc<AppType>("http://localhost:8787/", {
init: {
credentials: "include", // Required for sending cookies cross-origin
},
return c.json({ message: `Hello, ${session.user.name}.` });
});
// Now your client requests will include credentials
const response = await client.someProtectedEndpoint.$get();
export default app;
```
This configuration is necessary when:
This example applies the middleware to a single route. For other patterns, see Hono's [Middleware guide](https://hono.dev/docs/guides/middleware).
* Your client and server are on different domains/ports during development
* You're making cross-origin requests in production
* You need to send authentication cookies with your requests
## Hono RPC
The `credentials: "include"` option tells the fetch client to send cookies even for cross-origin requests. This works in conjunction with the CORS configuration on your server that has `credentials: true`.
The Better Auth client uses `credentials: "include"` by default. If you use Hono RPC to call authenticated Hono routes from another origin, configure the RPC client to include credentials as well:
> **Note:** Make sure your CORS configuration on the server matches your client's domain, and that `credentials: true` is set in both the server's CORS config and the client's fetch config.
<Tabs items={["Client", "Server"]}>
<Tab value="Client">
```ts title="src/client.ts"
import { hc } from "hono/client";
import type { AppType } from "./server";
const client = hc<AppType>("http://localhost:8787", {
init: { // [!code highlight]
credentials: "include", // [!code highlight]
}, // [!code highlight]
});
const response = await client.hello.$get();
```
</Tab>
<Tab value="Server">
```ts title="src/server.ts"
import { Hono } from "hono";
// Assume this route requires an authenticated session. // [!code highlight]
const app = new Hono().get("/hello", (c) => {
return c.json({ message: "Hello!" });
});
export type AppType = typeof app;
export default app;
```
</Tab>
</Tabs>
This configuration is only required for cross-origin requests. For more information, see Hono's [RPC cookies guide](https://hono.dev/docs/guides/rpc#cookies).