Better Auth on Cloudflare Workers with Hono and D1

better auth


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

Popular posts from this blog

Tutorial Expo React Native Google AdMob

Tutorial VNC Server on Linux Debian Bookworm

Tutorial React Navigation React Native