Better-auth cloudflare basics

 avatar
unknown
typescript
5 months ago
3.9 kB
31
Indexable
// index.ts
import honoFactory from "./hono-factory";
import { corsMiddleware } from "./middlewares/cors-middleware";
import { csrfMiddleware } from "./middlewares/csrf-middleware";
import { sessionMiddleware } from "./middlewares/session-middleware";

const routes = honoFactory
	.createApp()
	.basePath("/api")
	.use(corsMiddleware)
	.use(csrfMiddleware)
	.use(sessionMiddleware)
	.on(["POST", "GET"], "/auth/*", (c) => {
		return c.get("auth").handler(c.req.raw);
	})

export type HonoApp = typeof routes;
export default routes;

// hono-factory.ts
import { createFactory } from "hono/factory";
import { getAuth } from "@/lib/auth";
import { AppBindings } from "@/lib/types";
import { getDB } from "./db";

export default createFactory<AppBindings>({
	initApp: (app) => {
		app.use(async (c, next) => {
			const db = getDB(c);
			c.set("db", db);
			await next();
		});
		app.use(async (c, next) => {
			const auth = getAuth(c);
			c.set("auth", auth);
			await next();
		});
	}
});

// AppBindings type
import { DrizzleD1Database } from "drizzle-orm/d1";
import type { Session, User } from "better-auth";
import type { DBSchema } from "@/db";
import { getAuth } from "./auth";

export interface AppBindings extends Env {
	Bindings: {
		DB: D1Database;
		BETTER_AUTH_SECRET: string;
		BETTER_AUTH_URL: string;
		MODE: "development" | "production";
	};
	Variables: {
		auth: ReturnType<typeof getAuth>;
		db: DrizzleD1Database<DBSchema>;
		session: Session | null;
		user: User | null;
	};
}

// auth.ts
import { betterAuth, BetterAuthOptions } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { drizzle as drizzleD1 } from "drizzle-orm/d1";
import type { Context } from "hono";
import * as schema from "@/db/auth-schema.sql";
import type { AppBindings, ExtendedUser } from "./types";
import { ORIGINS } from "@/config/constants";

let authInstance: ReturnType<typeof betterAuth>;

export function getAuth(c: Context<AppBindings>) {
	if (!authInstance) {
		authInstance = betterAuth({
			trustedOrigins: ORIGINS,
			secret: c.env.BETTER_AUTH_SECRET,
			baseURL: c.env.BETTER_AUTH_URL,
			database: drizzleAdapter(
				drizzleD1(c.env.DB, {
					schema: {
						...schema
					}
				}),
				{
					provider: "sqlite",
				}
			),
		});
	}
	return authInstance;
}

// db.ts
import { type DrizzleD1Database, drizzle } from "drizzle-orm/d1";
import type { Context } from "hono";

import * as authSchema from "./auth-schema.sql";
import * as commandSchema from "./command-schema.sql";
import { AppBindings } from "@/lib/types";

export const schema = { ...authSchema, ...commandSchema };
export type DBSchema = typeof schema;

let dbInstance: DrizzleD1Database<DBSchema>;

export function getDB(c: Context<AppBindings>) {
	if (!dbInstance) {
		dbInstance = drizzle(c.env.DB, { schema });
	}
	return dbInstance;
}

// cors-middleware.ts
import { cors } from "hono/cors";

import { ORIGINS } from "@/config/constants";

export const corsMiddleware = cors({
	origin: ORIGINS,
	allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
	allowHeaders: ["Content-Type", "Cookie", "Authorization", "Access-Control-Allow-Origin"],
	credentials: true,
	maxAge: 600
});

// csrf-middleware.ts
import { csrf } from "hono/csrf";
import { ORIGINS } from "@/config/constants";

export const csrfMiddleware = csrf({
	origin: ORIGINS
});

// session-middleware.ts
import { getAuth } from "@/lib/auth";
import honoFactory from "../hono-factory";

export const sessionMiddleware = honoFactory.createMiddleware(async (c, next) => {
	const auth = getAuth(c);
	const userSession = await auth.api.getSession({
		headers: c.req.raw.headers
	});
	c.set("session", userSession?.session ?? null);
	c.set("user", userSession?.user ?? null);
	c.set("auth", auth);
	await next();
});
Editor is loading...
Leave a Comment