转载于:https://mp.weixin.qq.com/s/li5dsD1kXu6LFMT71bd3AQ
准备工作
- 创建hono项目
shell
lixiaobo@lixiaobodeMacBook-Pro cloudflare % npm create hono
> npx
> create-hono
create-hono version 0.19.4
✔ **Target directory** better-auth-cloudflare-demo
✔ **Which template do you want to use?** cloudflare-workers
✔ **Do you want to install project dependencies?** Yes
✔ **Which package manager do you want to use?** npm
✔ Cloning the template
✔ Installing project dependencies
🎉 **Copied project files**
Get started with: **cd better-auth-cloudflare-demo**
- 安装依赖
shell
npm install better-auth
- 在.dev.vars文件中配置SECRET_KEY_V1
- 可以在https://better-auth.com/docs/installation里面点击`Generate Secret`按钮生成
- 也可以使用
openssl rand -base64 32生成
- 编写sql文件
- better-auth需要
User、Session、Account和Verification四张表 - 可以使用npx @better-auth/cli generate生成
- 也可以在https://better-auth.com/docs/concepts/database#core-schema 手动拷贝SQLite版本的代码
- better-auth需要
sql
CREATE TABLE IF NOT EXISTS "user" (
"id" text NOT NULL PRIMARY KEY,
"name" text NOT NULL,
"email" text NOT NULL UNIQUE,
"emailVerified" integer NOT NULL,
"image" text,
"createdAt" date NOT NULL,
"updatedAt" date NOT NULL
);
CREATE TABLE IF NOT EXISTS "session" (
"id" text NOT NULL PRIMARY KEY,
"userId" text NOT NULL,
"token" text NOT NULL UNIQUE,
"expiresAt" date NOT NULL,
"ipAddress" text,
"userAgent" text,
"createdAt" date NOT NULL,
"updatedAt" date NOT NULL,
FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "account" (
"id" text NOT NULL PRIMARY KEY,
"userId" text NOT NULL,
"accountId" text NOT NULL,
"providerId" text NOT NULL,
"accessToken" text,
"refreshToken" text,
"accessTokenExpiresAt" date,
"refreshTokenExpiresAt" date,
"scope" text,
"idToken" text,
"password" text,
"createdAt" date NOT NULL,
"updatedAt" date NOT NULL,
FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "verification" (
"id" text NOT NULL PRIMARY KEY,
"identifier" text NOT NULL,
"value" text NOT NULL,
"expiresAt" date NOT NULL,
"createdAt" date NOT NULL,
"updatedAt" date NOT NULL
);
```
* 创建本地数据库
* 编辑wrangler.jsonc文件,添加d1_databases相关信息,本地运行的时候不存在"database_id",可以将其填为"00000000-0000-0000-0000-000000000000",线上运行的时候,按照真实填写
```json
"d1_databases": [
{
"binding": "DB",
"database_name": "better-auth-cloudflare-demo",
"database_id": ""
}
]
```
* 将上面的sql语句保存在better-auth-cloudflare-demo.sql文件里面并执行如下命令
```shell
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-demo % wrangler d1 execute better-auth-cloudflare-demo --local --file=better-auth-cloudflare-demo.sql
▲ [WARNING] **Proxy environment variables detected. We'll use your proxy for fetch requests.**
⛅️ wrangler 4.106.0
────────────────────
**Resource location:** local
Use --remote if you want to access the remote instance.
🌀 Executing on local database better-auth-cloudflare-demo () from .wrangler/state/v3/d1:
🌀 To execute on your remote database, add a --remote flag to your wrangler command.
🚣 4 commands executed successfully.
```
* 查看数据库是否生成成功
* npx localflare
* webstrom
* wrangler
```shell
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-demo % npx wrangler d1 execute DB --local --command="SELECT name FROM sqlite_master WHERE type='table';"
▲ [WARNING] **Proxy environment variables detected. We'll use your proxy for fetch requests.**
⛅️ wrangler 4.110.0
────────────────────
**Resource location:** local
Use --remote if you want to access the remote instance.
🌀 Executing on local database DB () from .wrangler/state/v3/d1:
🌀 To execute on your remote database, add a --remote flag to your wrangler command.
🚣 1 command executed successfully.
┌──────────────┐
│ name │
├──────────────┤
│ user │
├──────────────┤
│ session │
├──────────────┤
│ account │
├──────────────┤
│ verification │
├──────────────┤
│ _cf_METADATA
- 生成worker-configuration.d.ts
shell
wrangler types
编写代码
- src/lib/auth.ts
ts
import {betterAuth} from "better-auth"
export const createAuth = (env: Cloudflare.Env)=> betterAuth(
{
database: env.DB,
emailAndPassword: {
enabled: true,
},
secrets: [
{ version: 1, value: env.SECRET_KEY_V1 },
],
basePath: "/api/auth",
baseURL: {
allowedHosts: [
"localhost:*",
],
protocol: "auto",
},
}
);
export type AuthInstance = ReturnType<typeof createAuth>;
export type SessionUser = AuthInstance["$Infer"]["Session"]["user"];
- 创建路由src/routes/user.ts
ts
import {Hono} from 'hono'
import {createAuth, SessionUser} from "../lib/auth";
export const authRouter = new Hono<{Bindings: Cloudflare.Env, Variables: {user?:SessionUser}}>();
export const AuthRouterPrefix = "/api/auth";
// GET/POST /user/auth/*
authRouter.all("/*", (c) => {
const auth = createAuth(c.env);
return auth.handler(c.req.raw);
});
// middleware: /user/*
authRouter.use("/*", async (c, next) => {
const auth = createAuth(c.env);
const session = await auth.api.getSession({ headers: c.req.raw.headers });
c.set("user", session?.user);
await next();
});
// GET /api/me
authRouter.get("/me", async (c) => {
if (!c.get("user")) {
return c.json({ error: "unauthorized" }, 401);
}
return c.json(c.get("user")!);
});
- src/index.ts
ts
import { Hono } from 'hono'
import {createAuth, SessionUser} from "./lib/auth";
import {authRouter, AuthRouterPrefix} from "./routes/auth"
const app = new Hono<{Bindings: Cloudflare.Env, Variables: {user?:SessionUser}}>()
app.route(AuthRouterPrefix, authRouter);
console.log("=== 当前可用的 API 端点列表 ===");
app.routes.forEach(r => console.log(`[${r.method}]`.padEnd(8) + r.path));
console.log("===============================");
export default app
运行和测试
本地
运行
```shell
wrangler dev
```
测试
- 注册
shell
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-demo % curl -X POST http://localhost:8787/api/auth/sign-up/email \
-H 'Content-Type: application/json' \
-d '{"email":"test@example.com","password":"12345678","name":"test"}'
{"token":"OS57FCQgo9n3maerb7kKoXfD2RNwGBDK","user":{"name":"test","email":"test@example.com","emailVerified":false,"image":null,"createdAt":"2026-07-10T11:10:23.856Z","updatedAt":"2026-07-10T11:10:23.856Z","id":"cvdFAOWgxn6PMd3WD51pMUQoaDW6iw2F"}}
- 登录
shell
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-demo % curl -sS \
-X POST http://localhost:8787/api/auth/sign-in/email \
-H 'Content-Type: application/json' \
-d '{"email":"test@example.com","password":"12345678"}'
{"redirect":false,"token":"Var3ENBaJGZj4VQrpNzwta1cTtbxbUna","user":{"name":"test","email":"test@example.com","emailVerified":false,"image":null,"createdAt":"2026-07-10T11:10:23.856Z","updatedAt":"2026-07-10T11:10:23.856Z","id":"cvdFAOWgxn6PMd3WD51pMUQoaDW6iw2F"}}
- 错误密码登录
shell
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-demo % curl -sS \
-X POST http://localhost:8787/api/auth/sign-in/email \
-H 'Content-Type: application/json' \
-d '{"email":"test@example.com","password":"password123"}'
{"message":"Invalid email or password","code":"INVALID_EMAIL_OR_PASSWORD"}
- 不存在的用户登录
shell
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-demo % curl -sS \
-X POST http://localhost:8787/api/auth/sign-in/email \
-H 'Content-Type: application/json' \
-d '{"email":"nobody@example.com","password":"password123"}'
{"message":"Invalid email or password","code":"INVALID_EMAIL_OR_PASSWORD"
cloudflare运行
生成线上数据库
- 创建数据库
shell
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-demo % wrangler d1 create better-auth-cloudflare-demo
▲ [WARNING] **Proxy environment variables detected. We'll use your proxy for fetch requests.**
⛅️ wrangler 4.106.0 (update available 4.110.0)
───────────────────────────────────────────────
✅ Successfully created DB 'better-auth-cloudflare-demo' in region WNAM
Created your new D1 database.
To access your new D1 Database in your Worker, add the following snippet to your configuration file:
{
"d1_databases": [
{
"binding": "better_auth_cloudflare_demo",
"database_name": "better-auth-cloudflare-demo",
"database_id": "25b30dd3-b35d-45fa-9fa9-7c2af8240024"
}
]
}
✔ **Would you like Wrangler to add it on your behalf?** ... yes
✔ **What binding name would you like to use?** ... better_auth_cloudflare_demo
✔ **For local dev, do you want to connect to the remote resource instead of a local resource?** ... yes
- 将返回d1_databases信息,贴到wrangler.jsonc文件对应位置(默认应该会自动更新wrangler.jsonc,无须手动粘贴)
- 创建表
shell
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-demo % wrangler d1 execute better-auth-cloudflare-demo --remote --file=./better-auth-cloudflare-demo.sql
▲ [WARNING] **Proxy environment variables detected. We'll use your proxy for fetch requests.**
⛅️ wrangler 4.106.0 (update available 4.110.0)
───────────────────────────────────────────────
**Resource location:** remote
✔ **⚠️ This process may take some time, during which your D1 database will be unavailable to serve queries.**
**Ok to proceed?** ... yes
🌀 Executing on remote database better-auth-cloudflare-demo (25b30dd3-b35d-45fa-9fa9-7c2af8240024):
🌀 To execute on your local development database, remove the --remote flag from your wrangler command.
Note: if the execution fails to complete, your DB will return to its original state and you can safely retry.
├ 🌀 Uploading 25b30dd3-b35d-45fa-9fa9-7c2af8240024.f838ba309bc50ebd.sql
│ 🌀 Uploading complete.
│
🌀 Starting import...
🌀 Processed 4 queries.
🚣 Executed 4 queries in 5.36ms (4 rows read, 14 rows written)
Database is currently at bookmark 00000001-00000006-000050a4-51499d332507084e452c9586ed6634a2.
┌───────────────────────┬───────────┬──────────────┬───────────────────┐
│Total queries executed │ Rows read │ Rows written │ Database size (MB)│
├───────────────────────┼───────────┼──────────────┼───────────────────┤
│4 │ 4 │ 14 │ 0.05 │
└───────────────────────┴───────────┴──────────────┴───────────────────┘
发布到线上,也可以使用自己的域名
shell
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-demo % wrangler deploy
▲ [WARNING] **Proxy environment variables detected. We'll use your proxy for fetch requests.**
⛅️ wrangler 4.106.0 (update available 4.110.0)
───────────────────────────────────────────────
Total Upload: 1759.21 KiB / gzip: 304.34 KiB
Worker Startup Time: 47 ms
Your Worker has access to the following bindings:
Binding Resource
env.better_auth_cloudflare_demo (better-auth-cloudflare-demo) D1 Database
env.BETTER_AUTH_URL ("localhost") Environment Variable
Uploaded better-auth-cloudflare-demo (5.12 sec)
Deployed better-auth-cloudflare-demo triggers (1.95 sec)
https://better-auth-cloudflare-demo.shakingwaves.workers.dev
Current Version ID: 2fb6c9de-4448-4954-9209-81ab9402e908
- 修改wrangler.jsonc中BETTER_AUTH_URL为https://better-auth-cloudflare-demo.shakingwaves.workers.dev之后再次发布
- 将本地
.dev.vars里的密钥注入云端密文库
shell
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-demo % wrangler secret put SECRET_KEY_V1
▲ [WARNING] **Proxy environment variables detected. We'll use your proxy for fetch requests.**
⛅️ wrangler 4.106.0 (update available 4.110.0)
───────────────────────────────────────────────
✔ **Enter a secret value:** ... ********************************
🌀 Creating the secret for the Worker "better-auth-cloudflare-demo"
✨ Success! Uploaded secret SECRET_KEY_V1
- 测试,以此类推
shell
lixiaobo@lixiaobodeMacBook-Pro better-auth-cloudflare-demo % curl -X POST https://better-auth-cloudflare-demo.shakingwaves.workers.dev/api/auth/sign-up/email -H 'Content-Type: application/json' -d '{"email":"test@example.com","password":"12345678","name":"test"}'
{"token":"IBHF3ATPz4akhtFc05AqXgevqpkvq4Vn","user":{"name":"test","email":"test@example.com","emailVerified":false,"image":null,"createdAt":"2026-07-10T12:05:30.596Z","updatedAt":"2026-07-10T12:05:30.596Z","id":"tDVU8UApXsLcm8OZqeXJ6VtH3PZu1ena"}}
curl -sS -X POST https://better-auth-cloudflare-demo.shakingwaves.workers.dev/api/auth/sign-in/email -H 'Content-Type: application/json' -d '{"email":"test@example.com","password":"12345678"}'
{"redirect":false,"token":"nZNqQpSCzDWFwwJ1gCaokeYAgM5uxWOa","user":{"name":"test","email":"test@example.com","emailVerified":false,"image":null,"createdAt":"2026-07-10T12:05:30.596Z","updatedAt":"2026-07-10T12:05:30.596Z","id":"tDVU8UApXsLcm8OZqeXJ6VtH3PZu1ena"}}