Better Auth on Cloudflare Workers with Hono and D1
A TypeScript-based lightweight authentication service optimized for Cloudflare Workers
Stack Summary
🔥 Hono
A fast, lightweight web framework built on web standards.
🔒 Better Auth
A comprehensive authentication framework for TypeScript.
🧩 Drizzle ORM
A lightweight, high-performance ORM for TypeScript, built with DX in mind.
🐘 Cloudflare D1
A serverless Sqlite optimized for the cloud.
Installation
Hono
Select cloudflare-workers template
npm create hono
Better Auth
npm i better-auth
Drizzle ORM
npm i drizzle-orm
npm i -D drizzle-kit
Environment Variables
Set the following environment variables to connect your application to Better Auth.echo "BETTER_AUTH_URL=http://localhost:8787" >> .env
echo "BETTER_AUTH_SECRET=$(openssl rand -base64 32)" >> .env
cp .env .dev.vars
npx wrangler d1 create myDb --update-config
Required Files:
.dev.vars
Used by Wrangler in local development
In production, these should be set as Cloudflare Worker Secrets.
.env
Used for local development and CLI tools such as:
- Drizzle CLI
- Better Auth CLI
BETTER_AUTH_URL=
BETTER_AUTH_SECRET=
Wrangler
After setting your environment variables, run the following script to generate types for your Cloudflare Workers configuration:
npx wrangler types --env-interface CloudflareBindings
OR
npm run cf-typegen
Then, make sure your tsconfig.json includes the generated types.
tsconfig.json
{
"compilerOptions": {
"types": ["worker-configuration.d.ts"]
}
}
Drizzle
To use the Drizzle Kit CLI, add the following Drizzle configuration file to the root of your project.
drizzle.config.ts
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
out: './migrations',
schema: './src/db/auth-schema.ts',
dialect: 'sqlite',
});
Application
Better Auth Instance
Create a Better Auth instance using Cloudflare Workers bindings.
import { drizzle } from 'drizzle-orm/d1';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { betterAuth, BetterAuthOptions } from 'better-auth';
import { betterAuthOptions } from './auth-options';
/**
* Better Auth Instance
*/
export const auth = (env: CloudflareBindings): ReturnType<typeof betterAuth> => {
const db = drizzle(env.myDb);
const database = drizzleAdapter(db, {
provider: "sqlite",
});
const options: BetterAuthOptions = {
...betterAuthOptions,
database,
baseURL: env.BETTER_AUTH_URL,
secret: env.BETTER_AUTH_SECRET
};
return betterAuth(options);
};
There are many available configuration options, far more than can be covered in this example. Please refer to the official documentation and configure it according to your project’s needs:
(Docs: Better Auth - Options)
import { BetterAuthOptions } from 'better-auth';
/**
* Custom options for Better Auth
*
* Docs: https://www.better-auth.com/docs/reference/options
*/
export const betterAuthOptions: BetterAuthOptions = {
/**
* The name of the application.
*/
appName: 'YOUR_APP_NAME',
/**
* Base path for Better Auth.
* @default "/api/auth"
*/
basePath: '/api',
// .... More options
};
Better Auth Schema
To create the required tables for Better Auth, first add the following file to the root directory:
auth.ts
/**
* Better Auth CLI configuration file
*
* Docs: https://www.better-auth.com/docs/concepts/cli
*/
import { drizzle } from 'drizzle-orm/d1';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { betterAuth, BetterAuthOptions } from 'better-auth';
import { betterAuthOptions } from './src/lib/auth-options';
const { myDb, BETTER_AUTH_URL, BETTER_AUTH_SECRET } = process.env;
const db = drizzle(myDb!);
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "sqlite",
}),
baseURL: BETTER_AUTH_URL,
secret: BETTER_AUTH_SECRET
});
Then, execute the following script:
mkdir ./src/db & npx auth generate --output=\"./src/db/auth-schema.ts\" -y
Apply Schema to Database
After generating the schema file, run the following commands to create and apply the database migration: Check your wrangler config to read the process.env correctly for the wrangler dev to work later. You need node_compatibility setup.
npx drizzle-kit generate
npx wrangler d1 migrations apply myDb #this replaces drizzle-kit migrate
Mount the handler
Mount the Better Auth handler to a Hono endpoint, ensuring that the mount path matches the basePath setting in your Better Auth instance.
import { Hono } from 'hono';
import { auth } from './lib/better-auth';
const app = new Hono<{ Bindings: CloudflareBindings }>();
app.get('/', (c) => {
return c.json({ message: 'Welcome to the Hono + Better Auth + D1 example!' });
});
app.on(['GET', 'POST'], '/api/*', (c) => {
return auth(c.env).handler(c.req.raw);
});
app.get('/api/user', (c) => {
return c.json({ message: 'Authorized!' });
});
export default app
Comments
Post a Comment