Better Auth on Cloudflare β
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.
π Postgres with Neon
A serverless Postgres optimized for the cloud.
Preparation β
1. Installation β
# Hono
# > Select cloudflare-workers template
npm create hono
# Better Auth
npm install better-auth
# Drizzle ORM
npm install drizzle-orm
npm install --save-dev drizzle-kit
# Neon
npm install @neondatabase/serverless
# Hono
# > Select cloudflare-workers template
pnpm create hono
# Better Auth
pnpm add better-auth
# Drizzle ORM
pnpm add drizzle-orm
pnpm add -D drizzle-kit
# Neon
pnpm add @neondatabase/serverless
# Hono
# > Select cloudflare-workers template
yarn create hono
# Better Auth
yarn add better-auth
# Drizzle ORM
yarn add drizzle-orm
yarn add --dev drizzle-kit
# Neon
yarn add @neondatabase/serverless
# Hono
# > Select cloudflare-workers template
bun create hono
# Better Auth
bun add better-auth
# Drizzle ORM
bun add drizzle-orm
bun add -d drizzle-kit
# Neon
bun add @neondatabase/serverless
2. Environment Variables β
Set the following environment variables to connect your application to Better Auth and Neon.
Refer to official guides:
Required Files:
# Used by Wrangler in local development
# In production, these should be set as Cloudflare Worker Secrets.
BETTER_AUTH_URL=
BETTER_AUTH_SECRET=
DATABASE_URL=
# Used for local development and CLI tools such as:
#
# - Drizzle CLI
# - Better Auth CLI
BETTER_AUTH_URL=
BETTER_AUTH_SECRET=
DATABASE_URL=
3. 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
pnpm wrangler types --env-interface CloudflareBindings
# OR
pnpm cf-typegen
yarn wrangler types --env-interface CloudflareBindings
# OR
yarn cf-typegen
bunx wrangler types --env-interface CloudflareBindings
# OR
bun run cf-typegen
Then, make sure your tsconfig.json includes the generated types.
{
"compilerOptions": {
"types": ["worker-configuration.d.ts"]
}
}
4. Drizzle β
To use the Drizzle Kit CLI, add the following Drizzle configuration file to the root of your project.
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
out: './drizzle',
schema: './src/db/schema.ts',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
Application β
1. Better Auth Instance β
Create a Better Auth instance using Cloudflare Workers bindings.
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 { neon } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { betterAuth } from 'better-auth';
import { betterAuthOptions } from './options';
/**
* Better Auth Instance
*/
export const auth = (env: CloudflareBindings): ReturnType<typeof betterAuth> => {
const sql = neon(env.DATABASE_URL);
const db = drizzle(sql);
return betterAuth({
...betterAuthOptions,
database: drizzleAdapter(db, { provider: 'pg' }),
baseURL: env.BETTER_AUTH_URL,
secret: env.BETTER_AUTH_SECRET,
// Additional options that depend on env ...
});
};
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
};
2. Better Auth Schema β
To create the required tables for Better Auth, first add the following file to the root directory:
/**
* Better Auth CLI configuration file
*
* Docs: https://www.better-auth.com/docs/concepts/cli
*/
import { neon } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { betterAuth } from 'better-auth';
import { betterAuthOptions } from './src/lib/better-auth/options';
const { DATABASE_URL, BETTER_AUTH_URL, BETTER_AUTH_SECRET } = process.env;
const sql = neon(DATABASE_URL!);
const db = drizzle(sql);
export const auth: ReturnType<typeof betterAuth> = betterAuth({
...betterAuthOptions,
database: drizzleAdapter(db, { provider: 'pg' }),
baseURL: BETTER_AUTH_URL,
secret: BETTER_AUTH_SECRET,
});
Then, execute the following script:
npx @better-auth/cli@latest generate --config ./better-auth.config.ts --output ./src/db/schema.ts
pnpm dlx @better-auth/cli@latest generate --config ./better-auth.config.ts --output ./src/db/schema.ts
yarn dlx @better-auth/cli@latest generate --config ./better-auth.config.ts --output ./src/db/schema.ts
bunx @better-auth/cli@latest generate --config ./better-auth.config.ts --output ./src/db/schema.ts
3. Apply Schema to Database β
After generating the schema file, run the following commands to create and apply the database migration:
npx drizzle-kit generate
npx drizzle-kit migrate
pnpm drizzle-kit generate
pnpm drizzle-kit migrate
yarn drizzle-kit generate
yarn drizzle-kit migrate
bunx drizzle-kit generate
bunx drizzle-kit migrate
4. 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.on(['GET', 'POST'], '/api/*', (c) => {
return auth(c.env).handler(c.req.raw);
});
export default app;
Advanced β
This example is assembled based on the official documentation of Hono, Better Auth, and Drizzle. However, it goes beyond simple integration and offers the following benefits:
- Efficient development through integration of Cloudflare CLI, Better Auth CLI, and Drizzle CLI.
- Seamless transition between development and production environments.
- Apply changes consistently using a script.
You can extend this setup with custom scripts tailored to your workflow. For example:
{
"scripts": {
"dev": "wrangler dev",
"deploy": "pnpm run cf-gen-types && wrangler secret bulk .dev.vars.production && wrangler deploy --minify",
"cf-gen-types": "wrangler types --env-interface CloudflareBindings",
"better-auth-gen-schema": "pnpm dlx @better-auth/cli@latest generate --config ./better-auth.config.ts --output ./src/db/schema.ts"
},
}
NOTE:
Refer to the official CLI documentation for each tool for advanced usage and the most up-to-date options:
In Closing β
You now have a lightweight, fast, and comprehensive authentication service running on Cloudflare Workers. By leveraging Service Bindings, this setup allows you to build microservice-based architectures with minimal latency.
This guide demonstrates only a basic example, so for advanced use cases like OAuth or rate limiting, refer to the official documentation and tailor the configuration to your serviceβs needs.
You can find the full example source code here:
GitHub Repository