一键导入
auth-setup
Install Better Auth on Drizzle + D1 for one or more services. Triggers - "set up auth", "log in", "sign up", "add auth". Requires db-setup first.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Install Better Auth on Drizzle + D1 for one or more services. Triggers - "set up auth", "log in", "sign up", "add auth". Requires db-setup first.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Install Better Auth on Drizzle + D1 for one or more services. Triggers - "set up auth", "log in", "sign up", "add auth". Requires db-setup first.
D1 database setup with Drizzle ORM. Triggers - "connect DB", "set up database", "add D1", or when DB needed.
First project request - confirm direction and guide. Triggers on first request of a new project.
Refactor project based on .ai.md guidelines. Triggers - "refactor it", "refactor"
R2 object storage setup for server-side file uploads. Triggers - "image upload", "photo upload", "file upload", "save image", "save file", "upload feature", "storage", or any time a file/image upload is requested.
D1 database setup with Drizzle ORM. Triggers - "connect DB", "set up database", "add D1", or when DB needed.
| name | auth-setup |
| description | Install Better Auth on Drizzle + D1 for one or more services. Triggers - "set up auth", "log in", "sign up", "add auth". Requires db-setup first. |
Set up per-service authentication using Better Auth with Drizzle ORM on SQLite (D1). Each service (app, admin, supplier, …) gets its own prefixed tables, cookies, base path, and auth instance.
Previously this skill tried to do heavy string templating inside a shell script. That proved fragile across macOS vs Linux sed. Now: the script does only the trivial shell work, and YOU (the AI) handle every file creation and edit, reading the .ref files in assets/ as reference templates and substituting placeholders yourself.
db-setup completed. Verify with npm pkg get cg.plugins.db — it should print a config object, not undefined/{}.app (end users) and admin (operators).Apply these consistently when substituting placeholders in the .ref files. Do the substitution yourself — do not try to drive it with sed \U or similar, since BSD sed (macOS) does not support case folding.
| Placeholder | Meaning | Example for app | Example for admin |
|---|---|---|---|
{service} | lower-case service name | app | admin |
{Service} | PascalCase, first letter upper | App | Admin |
{SERVICE} | UPPER_SNAKE | APP | ADMIN |
{basePath} | Better Auth base path | /app/api/auth | /admin/api/auth |
{homePath} | post-signIn/signUp redirect path (service home) | / | /admin |
{loginPath} | post-signOut redirect path (login screen) | /login | /admin/login |
Repeat steps 1–6 for each target service. Steps 7–9 run once at the end.
bash .claude/skills/auth-setup/scripts/setup.sh <service1> [service2] ...
This only creates directories and prints a random 64-char hex secret per service. It does NOT generate any TS files. Capture the printed secret(s); you will paste them into src/server/config.ts in step 2.
src/server/config.tsAdd one entry per service inside the } as const; block, using the secret from step 1:
{SERVICE}_AUTH_SECRET: "<secret>",
Use Edit, not sed, so you can place it exactly before } as const;.
Reference: assets/auth-schema.ts.ref.
Copy the reference into src/server/db/plugin/auth/{service}-schema.ts, replacing every {service} and {Service} as above.
Critical:
import 'server-only' line. drizzle-kit loads this file during pnpm drizzle-kit generate/migrate in a plain Node context; server-only makes it throw. The reference already omits it; keep it that way.src/server/db/plugin/** are the only repository-layer files exempt from the server-only convention. Repository files that CONSUME these tables still import server-only.Append to src/server/db/schema.ts:
export * from "./plugin/auth/{service}-schema"
Reference: assets/auth-server.ts.ref.
Copy into src/server/auth/{service}.ts, substituting placeholders. Exports get{Service}Auth and get{Service}ServerSession.
Critical:
Better Auth's Drizzle adapter looks up tables by the EXACT keys user, session, account, verification. Because our tables are prefixed ({service}_auth__user, etc.), the adapter must receive an explicit mapping. The reference already shows the correct shape:
database: drizzleAdapter(db, {
provider: "sqlite",
schema: {
user: {service}AuthUser,
session: {service}AuthSession,
account: {service}AuthAccount,
verification: {service}AuthVerification,
},
}),
Do NOT shortcut this with import * as schema from "@/server/db/schema" followed by schema: schema. At runtime Better Auth will throw [# Drizzle Adapter]: The model "user" was not found in the schema object.
assets/auth-client.ts.ref → copy to src/lib/auth-client/{service}.ts.assets/auth-route.ts.ref → copy to src/app/({service})/{service}/api/auth/[...all]/route.ts.Cookie compat note: auth-server.ts issues SameSite=None; Secure cookies so
the app works inside an HTTPS iframe (preview). Direct http://localhost:3000
access also works because modern browsers treat localhost as a secure context
and accept Secure cookies over plain HTTP. No per-request rewriting needed.
If the project was scaffolded with mock state/auth files, swap them for the real ones:
src/services/{service}/state/user/actions/auth.ts ← reference assets/auth-actions.ts.refsrc/services/{service}/api/user/actions/get-me.ts ← reference assets/get-me.ts.refBoth references use {service}Auth / get{Service}ServerSession you created in steps 5–6. Adapt the User shape and hook name if the state domain uses a prefixed hook (e.g. useAdminUser) or if the admin service omits signUp.
If the project has a member profile table (e.g. {service}_member_profile) keyed by the auth user id, extend getMe to join that table and return the enriched user.
pnpm drizzle-kit generate
pnpm drizzle-kit migrate
Use pnpm, not npx. CLAUDE.md mandates pnpm for drizzle commands.
npm pkg set cg.plugins.auth.createdAt="$(date -Iseconds)" cg.plugins.auth.provider="better-auth"
.tools/start-dev-server.sh 3000
rm -rf .claude/skills/auth-setup
After auth is wired up, do not create src/middleware.ts to guard routes. Edge middleware can only inspect cookie names; it cannot verify session signatures, detect expiry, or see revoked sessions. Guard in a Server Component layout instead:
Group protected routes under a route group, e.g. src/app/({service})/(protected)/... or src/app/({service})/{service}/(protected)/....
Keep login / signup pages OUTSIDE that group.
Create {...}/(protected)/layout.tsx:
import { redirect } from 'next/navigation'
import { get{Service}ServerSession } from '@/server/auth/{service}'
export default async function ProtectedLayout({ children }: { children: React.ReactNode }) {
const session = await get{Service}ServerSession()
if (!session?.user) redirect('/login')
return <>{children}</>
}
Trade-off: you lose a next=<original-path> query on the redirect (RSCs cannot read the current pathname without middleware). Accept this for MVP; users navigate back manually after login.
sed \U does not work on macOS BSD sed.import 'server-only' in Drizzle schema: breaks pnpm drizzle-kit generate/migrate. Never add it under src/server/db/plugin/**.user/session/account/verification. Shortcut schema: schema fails at runtime.pnpm drizzle-kit …, not npx drizzle-kit ….Projects that add a {service}_member_profile table should key it by the auth user id:
id = session.user.id.getMe joins the profile table and returns the merged object.