Effect Integration
Integrate Better Auth with an Effect HTTP server.
Better Auth uses Web Standard Request and Response objects. Effect 4 can mount auth.handler with HttpEffect.fromWebHandler.
Before you begin, configure a Better Auth instance.
Install Effect
npm install effectIf you're starting a new Effect project, follow the Effect installation guide.
Mount the auth handler
The example below runs on Node.js. See the Effect Platform guide to use another runtime.
npm install @effect/platform-nodeimport { createServer } from "node:http";
import { NodeHttpServer, NodeRuntime } from "@effect/platform-node";
import { Layer } from "effect";
import { HttpEffect, HttpRouter, HttpServerResponse } from "effect/http";
import { auth } from "./auth.ts";
const homeRoute = HttpRouter.add(
"GET",
"/",
HttpServerResponse.text("Hello Better Auth"),
);
const authRoutes = HttpRouter.add(
"*",
"/api/auth/*", // Match your Better Auth basePath.
HttpEffect.fromWebHandler(auth.handler),
);
const routes = Layer.mergeAll(homeRoute, authRoutes);
const server = HttpRouter.serve(routes).pipe(
Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 })),
);
Layer.launch(server).pipe(NodeRuntime.runMain);Cross-origin requests
If your frontend runs on a different origin, allow it in both the Effect server's CORS middleware and Better Auth's trustedOrigins. The middleware applies to every route, so list only the origins that need cookie access.
import { betterAuth } from "better-auth";
export const auth = betterAuth({
trustedOrigins: ["http://localhost:5173"],
});import { HttpMiddleware } from "effect/http";
const server = HttpRouter.serve(routes, {
middleware: HttpMiddleware.cors({
allowedOrigins: ["http://localhost:5173"],
credentials: true,
}),
}).pipe(
Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 })),
);For cross-site cookies, see Cookies.
Protect application routes
You can protect application resources by checking the session with Better Auth:
import { Effect } from "effect";
import { HttpServerRequest, HttpServerResponse } from "effect/http";
const profileRoute = HttpRouter.add(
"GET",
"/profile",
Effect.gen(function* () {
const request = yield* HttpServerRequest.HttpServerRequest;
const session = yield* Effect.tryPromise(() =>
auth.api.getSession({ headers: request.headers }),
);
if (!session) {
return HttpServerResponse.empty({ status: 401 });
}
return yield* HttpServerResponse.json(session.user);
}),
);
const routes = Layer.mergeAll(homeRoute, authRoutes, profileRoute);