better-auth について
フレームワークに依存しないTypeScript認証・認可ライブラリ、better-authを扱うスキルです。設定、データベース連携、高度な認証機能、移行方法を案内します。
主な機能
- 01TypeScriptアプリの認証設定
- 02D1などのデータベース連携
- 03二要素認証とパスキーの追加
- 04組織とマルチテナントの管理
- 05ソーシャルログインとレート制限の設定
- 06移行ガイドの活用
活用シーン
- 01D1を使うCloudflare Workersアプリの認証設定
- 02SaaSアプリへの組織機能の追加
- 03ClerkまたはAuth.jsからのアプリ移行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jackspace/ claudeskillz --skill better-authインストール後、Claude Code で/better-authを入力して読み込まれたか確認します。
同梱ファイルREADME.mdSKILL.json
詳細
better-auth スキル
概要
better-auth は、TypeScript 向けの包括的でフレームワークに依存しない認証・認可ライブラリです。Cloudflare D1 を第一級でサポートする完全な認証ソリューションを提供し、Clerk や Auth.js に代わる優れたセルフホスト可能な選択肢です。
このスキルを使用する場面:
- Cloudflare Workers + D1 アプリケーションの認証を構築する場合
- セルフホスト可能で、特定のベンダーに依存しない認証ソリューションが必要な場合
- Clerk から移行する場合(ベンダーロックインを回避)
- Auth.js からアップグレードする場合(より多くの機能が必要)
- 組織やチームを備えたマルチテナント SaaS を実装する場合
- 2FA、パスキー、RBAC、ソーシャル認証などの高度な機能が必要な場合
パッケージ:[email protected](2025-10-31 時点で最新確認済み)
インストール
コアパッケージ
npm install better-auth
# or
pnpm add better-auth
# or
yarn add better-auth
データベースアダプター
Cloudflare D1 用(Workers):
npm install @cloudflare/workers-types
PostgreSQL 用:
npm install pg drizzle-orm
MySQL/SQLite 用:組み込みアダプターがあるため、追加パッケージは不要です。
ソーシャルプロバイダー(任意)
npm install @better-auth/google
npm install @better-auth/github
npm install @better-auth/microsoft
クイックスタートのパターン
パターン 1:Cloudflare Workers + D1
使用場面:D1 データベースを使用して Cloudflare Workers 上に API を構築する場合
ファイル:src/worker.ts
import { betterAuth } from 'better-auth'
import { d1Adapter } from 'better-auth/adapters/d1'
import { Hono } from 'hono'
type Env = {
DB: D1Database
BETTER_AUTH_SECRET: string
GOOGLE_CLIENT_ID: string
GOOGLE_CLIENT_SECRET: string
}
const app = new Hono<{ Bindings: Env }>()
// Auth routes handler
app.all('/api/auth/*', async (c) => {
const auth = betterAuth({
database: d1Adapter(c.env.DB),
secret: c.env.BETTER_AUTH_SECRET,
// Basic auth methods
emailAndPassword: {
enabled: true,
requireEmailVerification: true
},
// Social providers
socialProviders: {
google: {
clientId: c.env.GOOGLE_CLIENT_ID,
clientSecret: c.env.GOOGLE_CLIENT_SECRET
}
}
})
return auth.handler(c.req.raw)
})
export default app
wrangler.toml:
name = "my-app"
main = "src/worker.ts"
compatibility_date = "2024-01-01"
[[d1_databases]]
binding = "DB"
database_name = "my-app-db"
database_id = "your-database-id"
[vars]
# Public vars here
# Secrets (use: wrangler secret put BETTER_AUTH_SECRET)
# - BETTER_AUTH_SECRET
# - GOOGLE_CLIENT_ID
# - GOOGLE_CLIENT_SECRET
D1 データベースのセットアップ:
# Create database
wrangler d1 create my-app-db
# Generate migration SQL from better-auth
npx better-auth migrate --database d1
# Apply migration
wrangler d1 execute my-app-db --remote --file migrations/0001_initial.sql
パターン 2:Next.js API ルート
使用場面:PostgreSQL または D1 を使用する従来型の Next.js アプリを構築する場合
ファイル:src/lib/auth.ts
import { betterAuth } from 'better-auth'
import { Pool } from 'pg'
export const auth = betterAuth({
database: new Pool({
connectionString: process.env.DATABASE_URL
}),
secret: process.env.BETTER_AUTH_SECRET!,
emailAndPassword: {
enabled: true,
requireEmailVerification: true,
sendVerificationEmail: async ({ user, url }) => {
// Send email with verification link
await sendEmail({
to: user.email,
subject: 'Verify your email',
html: `Click <a href="${url}">here</a> to verify`
})
}
},
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!
},
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!
}
},
// Advanced features via plugins
plugins: [
twoFactor(),
organization(),
rateLimit()
]
})
ファイル:src/app/api/auth/[...all]/route.ts
import { auth } from '@/lib/auth'
export const GET = auth.handler
export const POST = auth.handler
パターン 3:React クライアントの統合
使用場面:クライアント側で認証状態やアクションが必要な場合
ファイル:src/lib/auth-client.ts
import { createAuthClient } from 'better-auth/client'
export const authClient = createAuthClient({
baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000'
})
ファイル:src/components/LoginForm.tsx
'use client'
import { authClient } from '@/lib/auth-client'
import { useState } from 'react'
export function LoginForm() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
const { data, error } = await authClient.signIn.email({
email,
password
})
if (error) {
console.error('Login failed:', error)
return
}
// Redirect or update UI
window.location.href = '/dashboard'
}
const handleGoogleSignIn = async () => {
await authClient.signIn.social({
provider: 'google',
callbackURL: '/dashboard'
})
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Sign In</button>
<button type="button" onClick={handleGoogleSignIn}>
Sign in with Google
</button>
</form>
)
}
React フックを使用する(セッションエンドポイントがある場合):
'use client'
import { useSession } from 'better-auth/client'
export function UserProfile() {
const { data: session, isPending } = useSession()
if (isPending) return <div>Loading...</div>
if (!session) return <div>Not authenticated</div>
return (
<div>
<p>Welcome, {session.user.email}</p>
<button onClick={() => authClient.signOut()}>
Sign Out
</button>
</div>
)
}
パターン 4:保護された API ルート(ミドルウェア)
使用場面:API ルートでセッションを検証する必要がある場合
Cloudflare Workers:
import { betterAuth } from 'better-auth'
import { d1Adapter } from 'better-auth/adapters/d1'
app.get('/api/protected', async (c) => {
const auth = betterAuth({
database: d1Adapter(c.env.DB),
secret: c.env.BETTER_AUTH_SECRET
})
const session = await auth.getSession(c.req.raw)
if (!session) {
return c.json({ error: 'Unauthorized' }, 401)
}
return c.json({
message: 'Protected data',
user: session.user
})
})
Next.js ミドルウェア:
// middleware.ts
import { NextRequest, NextResponse } from 'next/server'
import { auth } from '@/lib/auth'
export async function middleware(request: NextRequest) {
const session = await auth.getSession(request)
if (!session && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*']
}
高度な機能
二要素認証(2FA)
import { betterAuth } from 'better-auth'
import { twoFactor } from 'better-auth/plugins'
export const auth = betterAuth({
database: /* ... */,
plugins: [
twoFactor({
methods: ['totp', 'sms'], // Time-based or SMS
issuer: 'MyApp'
})
]
})
クライアント:
// Enable 2FA for user
const { data, error } = await authClient.twoFactor.enable({
method: 'totp'
})
// Verify code
await authClient.twoFactor.verify({
code: '123456'
})
組織とチーム
import { betterAuth } from 'better-auth'
import { organization } from 'better-auth/plugins'
export const auth = betterAuth({
database: /* ... */,
plugins: [
organization({
roles: ['owner', 'admin', 'member'],
permissions: {
admin: ['read', 'write', 'delete'],
member: ['read']
}
})
]
})
クライアント:
// Create organization
await authClient.organization.create({
name: 'Acme Corp',
slug: 'acme'
})
// Invite member
await authClient.organization.inviteMember({
organizationId: 'org_123',
email: '[email protected]',
role: 'member'
})
// Check permissions
const canDelete = await authClient.organization.hasPermission({
organizationId: 'org_123',
permission: 'delete'
})
マルチテナント SaaS
import { betterAuth } from 'better-auth'
import { multiTenant } from 'better-auth/plugins'
export const auth = betterAuth({
database: /* ... */,
plugins: [
multiTenant({
tenantIdHeader: 'x-tenant-id',
isolateData: true // Ensure tenant data isolation
})
]
})
レート制限
import { betterAuth } from 'better-auth'
import { rateLimit } from 'better-auth/plugins'
export const auth = betterAuth({
database: /* ... */,
plugins: [
rateLimit({
window: 60, // 60 seconds
max: 5, // 5 requests per window
storage: 'database' // or 'memory'
})
]
})
Cloudflare の場合:分散レート制限には KV を使用します:
import { rateLimit } from 'better-auth/plugins'
plugins: [
rateLimit({
window: 60,
max: 5,
storage: {
get: async (key) => {
return await c.env.RATE_LIMIT_KV.get(key)
},
set: async (key, value, ttl) => {
await c.env.RATE_LIMIT_KV.put(key, value, { expirationTtl: ttl })
}
}
})
]
データベースのセットアップ
D1 スキーマのマイグレーション
# Generate migration
npx better-auth migrate --database d1
# This creates: migrations/0001_initial.sql
マイグレーションを適用する:
# Local
wrangler d1 execute my-app-db --local --file migrations/0001_initial.sql
# Production
wrangler d1 execute my-app-db --remote --file migrations/0001_initial.sql
手動でのスキーマ設定(必要な場合):
-- better-auth core tables
CREATE TABLE users (
id TEXT PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
emailVerified INTEGER DEFAULT 0,
name TEXT,
image TEXT,
createdAt INTEGER NOT NULL,
updatedAt INTEGER NOT NULL
);
CREATE TABLE sessions (
id TEXT PRIMARY KEY,
userId TEXT NOT NULL,
expiresAt INTEGER NOT NULL,
ipAddress TEXT,
userAgent TEXT,
FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE accounts (
id TEXT PRIMARY KEY,
userId TEXT NOT NULL,
provider TEXT NOT NULL,
providerAccountId TEXT NOT NULL,
accessToken TEXT,
refreshToken TEXT,
expiresAt INTEGER,
FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE verification_tokens (
identifier TEXT NOT NULL,
token TEXT NOT NULL,
expires INTEGER NOT NULL,
PRIMARY KEY (identifier, token)
);
-- Additional tables for plugins (organizations, 2FA, etc.)
Drizzle を使用した PostgreSQL
ファイル:src/db/schema.ts
import { pgTable, text, timestamp, boolean } from 'drizzle-orm/pg-core'
export const users = pgTable('users', {
id: text('id').primaryKey(),
email: text('email').unique().notNull(),
emailVerified: boolean('email_verified').default(false),
name: text('name'),
image: text('image'),
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at').notNull().defaultNow()
})
// ... other tables
セットアップ:
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
import { betterAuth } from 'better-auth'
const client = postgres(process.env.DATABASE_URL!)
const db = drizzle(client)
export const auth = betterAuth({
database: db,
// ...
})
ソーシャルプロバイダーのセットアップ
Google OAuth
- OAuth 認証情報を作成する:https://console.cloud.google.com/apis/credentials
- 承認済みリダイレクト URI:
https://yourdomain.com/api/auth/callback/google - 環境変数:
GOOGLE_CLIENT_ID=your-client-id GOOGLE_CLIENT_SECRET=your-client-secret
設定:
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
scope: ['email', 'profile'] // Optional
}
}
GitHub OAuth
- OAuth アプリを作成する:https://github.com/settings/developers
- 認証コールバック URL:
https://yourdomain.com/api/auth/callback/github - 環境変数:
GITHUB_CLIENT_ID=your-client-id GITHUB_CLIENT_SECRET=your-client-secret
設定:
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!
}
}
Microsoft OAuth
npm install @better-auth/microsoft
- Azure ポータル:https://portal.azure.com → アプリの登録
- リダイレクト URI:
https://yourdomain.com/api/auth/callback/microsoft - 環境変数:
MICROSOFT_CLIENT_ID=your-client-id MICROSOFT_CLIENT_SECRET=your-client-secret MICROSOFT_TENANT_ID=common # or your tenant ID
設定:
import { microsoft } from '@better-auth/microsoft'
socialProviders: {
microsoft: microsoft({
clientId: process.env.MICROSOFT_CLIENT_ID!,
clientSecret: process.env.MICROSOFT_CLIENT_SECRET!,
tenantId: process.env.MICROSOFT_TENANT_ID!
})
}
移行ガイド
Clerk からの移行
主な違い:
- Clerk:サードパーティサービス → better-auth:セルフホスト可能
- Clerk:プロプライエタリ → better-auth:オープンソース
- Clerk:月額料金 → better-auth:無料
移行手順:
- Clerk からユーザーデータをエクスポートする(CSV または API)
- better-auth のデータベースにインポートする:
// migration script const clerkUsers = await fetchClerkUsers() for (const clerkUser of clerkUsers) { await db.insert(users).values({ id: clerkUser.id, email: clerkUser.email, emailVerified: clerkUser.email_verified, name: clerkUser.first_name + ' ' + clerkUser.last_name, image: clerkUser.profile_image_url }) } - Clerk SDK を better-auth クライアントに置き換える:
// Before (Clerk) import { useUser } from '@clerk/nextjs' const { user } = useUser() // After (better-auth) import { useSession } from 'better-auth/client' const { data: session } = useSession() const user = session?.user - セッション検証用にミドルウェアを更新する
- ソーシャルプロバイダーを設定する(OAuth アプリは同じものを使用し、設定のみ変更)
Auth.js(NextAuth)からの移行
主な違い:
- Auth.js:機能が限定的 → better-auth:包括的(2FA、組織など)
- Auth.js:コールバック中心 → better-auth:プラグインベース
- Auth.js:セッション処理にばらつきがある → better-auth:一貫性がある
移行手順:
- データベーススキーマ:Auth.js と better-auth は似たスキーマを使用しますが、カラム名が異なります
-- Map Auth.js to better-auth ALTER TABLE users RENAME COLUMN emailVerified TO email_verified; -- etc. - 設定を置き換える:
// Before (Auth.js) import NextAuth from 'next-auth' import GoogleProvider from 'next-auth/providers/google' export default NextAuth({ providers: [GoogleProvider({ /* ... */ })] }) // After (better-auth) import { betterAuth } from 'better-auth' export const auth = betterAuth({ socialProviders: { google: { /* ... */ } } }) - クライアントフックを更新する:
// Before import { useSession } from 'next-auth/react' // After import { useSession } from 'better-auth/client'
既知の問題と解決策
問題 1:D1 の結果整合性
問題:D1 では、書き込み直後にセッションを読み取ると、古いデータが返されることがあります。
症状:ユーザーがログインしたのに、次のリクエストで getSession() が null を返します。
解決策:セッションの保存には、強い整合性を持つ Cloudflare KV を使用します:
import { betterAuth } from 'better-auth'
export const auth = betterAuth({
database: d1Adapter(env.DB), // Users, accounts
session: {
storage: {
get: async (sessionId) => {
const session = await env.SESSIONS_KV.get(sessionId)
return session ? JSON.parse(session) : null
},
set: async (sessionId, session, ttl) => {
await env.SESSIONS_KV.put(
sessionId,
JSON.stringify(session),
{ expirationTtl: ttl }
)
},
delete: async (sessionId) => {
await env.SESSIONS_KV.delete(sessionId)
}
}
}
})
参照元:https://github.com/better-auth/better-auth/issues/147
問題 2:SPA アプリケーションの CORS
問題:認証 API とフロントエンドのオリジンが異なる場合、CORS エラーが発生します。
症状:ブラウザーのコンソールに Access-Control-Allow-Origin エラーが表示されます。
解決策:Worker で CORS ヘッダーを設定します:
import { Hono } from 'hono'
import { cors } from 'hono/cors'
const app = new Hono<{ Bindings: Env }>()
app.use('/api/auth/*', cors({
origin: ['https://yourdomain.com', 'http://localhost:3000'],
credentials: true, // Allow cookies
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']
}))
app.all('/api/auth/*', async (c) => {
const auth = betterAuth({ /* ... */ })
return auth.handler(c.req.raw)
})
参照元:https://better-auth.com/docs/guides/cors
問題 3:Worker でのセッションのシリアライズ
問題:Cloudflare Workers で複雑なセッションオブジェクトをシリアライズできません。
症状:DataCloneError が発生するか、セッションデータが失われます。
解決策:セッションデータを最小限にし、JSON でシリアライズ可能な形式にします:
export const auth = betterAuth({
database: d1Adapter(env.DB),
session: {
// Only include serializable fields
fields: {
userId: true,
email: true,
role: true
// Don't include: functions, Dates, complex objects
}
}
})
問題 4:OAuth リダイレクト URI の不一致
問題:「redirect_uri_mismatch」エラーが発生し、ソーシャルログインに失敗します。
症状:ユーザーが同意した後、Google/GitHub OAuth がエラーを返します。
解決策:OAuth プロバイダーの設定と完全に一致させます:
Provider setting: https://yourdomain.com/api/auth/callback/google
better-auth URL: https://yourdomain.com/api/auth/callback/google
❌ Wrong: http vs https, trailing slash, subdomain mismatch
✅ Right: Exact character-for-character match
better-auth のコールバック URL を確認します:
// It's always: {baseURL}/api/auth/callback/{provider}
const callbackURL = `${process.env.NEXT_PUBLIC_API_URL}/api/auth/callback/google`
console.log('Configure this URL in Google Console:', callbackURL)
問題 5:メール確認メールが送信されない
問題:メール確認リンクが届きません。
症状:ユーザーが登録しても、メールが届きません。
解決策:sendVerificationEmail ハンドラーを実装します:
export const auth = betterAuth({
database: /* ... */,
emailAndPassword: {
enabled: true,
requireEmailVerification: true,
sendVerificationEmail: async ({ user, url, token }) => {
// Use your email service (SendGrid, Resend, etc.)
await sendEmail({
to: user.email,
subject: 'Verify your email',
html: `
<p>Click the link below to verify your email:</p>
<a href="${url}">Verify Email</a>
<p>Or use this code: ${token}</p>
`
})
}
}
})
Cloudflare の場合:Cloudflare Email Routing または外部サービス(Resend、SendGrid)を使用します。
問題 6:JWT トークンの有効期限
問題:セッションの有効期限が短すぎる、または期限切れになりません。
症状:ユーザーが予期せずログアウトされる、またはログアウト後もセッションが維持されます。
解決策:セッションの有効期限を設定します:
export const auth = betterAuth({
database: /* ... */,
session: {
expiresIn: 60 * 60 * 24 * 7, // 7 days (in seconds)
updateAge: 60 * 60 * 24 // Update session every 24 hours
}
})
問題 7:パスワードハッシュ化のパフォーマンス
問題:Cloudflare Workers でのサインアップ/ログインが遅くなります。
症状:認証リクエストに 1 秒以上かかります。
解決策:better-auth はデフォルトで CPU 負荷の高い bcrypt を使用します。Workers では、適切な非同期処理が行われるようにします:
// better-auth handles this internally, but if custom:
import bcrypt from 'bcryptjs'
// Use async version (not sync)
const hash = await bcrypt.hash(password, 10) // ✅
const isValid = await bcrypt.compare(password, hash) // ✅
// Don't use:
const hash = bcrypt.hashSync(password, 10) // ❌ (blocks)
代替策:better-auth に組み込まれているハッシュ化機能を使用します(すでに最適化されています)。
問題 8:ソーシャルプロバイダーのスコープに関する問題
問題:ソーシャルログインは成功しますが、ユーザーデータ(名前、アバター)が不足しています。
症状:Google/GitHub でログインした後、session.user.name が null になります。
解決策:追加のスコープをリクエストします:
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
scope: ['openid', 'email', 'profile'] // Include 'profile' for name/image
},
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
scope: ['user:email', 'read:user'] // 'read:user' for full profile
}
}
問題 9:マルチテナントのデータ漏えい
問題:ユーザーが他のテナントのデータを閲覧できます。
症状:組織 A のユーザーが組織 B のデータを閲覧できます。
解決策:クエリでは必ずテナント ID でフィルターします:
import { multiTenant } from 'better-auth/plugins'
export const auth = betterAuth({
database: /* ... */,
plugins: [
multiTenant({
tenantIdHeader: 'x-tenant-id',
isolateData: true // Enforces tenant isolation
})
]
})
// In API routes
app.get('/api/data', async (c) => {
const session = await auth.getSession(c.req.raw)
const tenantId = c.req.header('x-tenant-id')
// ALWAYS filter by tenant
const data = await db.query.items.findMany({
where: eq(items.tenantId, tenantId)
})
return c.json(data)
})
問題 10:レート制限による誤検知
問題:正当なユーザーがレート制限によってブロックされます。
症状:通常の利用で「リクエストが多すぎます」というエラーが発生します。
解決策:レート制限キーには IP とユーザー ID を使用します:
import { rateLimit } from 'better-auth/plugins'
plugins: [
rateLimit({
window: 60,
max: 10,
keyGenerator: (req) => {
// Combine IP and user ID (if authenticated)
const ip = req.headers.get('cf-connecting-ip') || 'unknown'
const userId = req.session?.userId || 'anonymous'
return `${ip}:${userId}`
}
})
]
比較:better-auth と代替製品
| 機能 | better-auth | Clerk | Auth.js |
|---|---|---|---|
| ホスティング | セルフホスト可能 | サードパーティ | セルフホスト可能 |
| 費用 | 無料(OSS) | $25/mo+ | 無料(OSS) |
| Cloudflare D1 | ✅ ファーストクラス | ❌ なし | ✅ アダプター |
| ソーシャル認証 | ✅ 10+ プロバイダー | ✅ 多数 | ✅ 多数 |
| 2FA/パスキー | ✅ プラグイン | ✅ 組み込み | ⚠️ 限定的 |
| 組織 | ✅ プラグイン | ✅ 組み込み | ❌ なし |
| マルチテナント | ✅ プラグイン | ✅ 対応 | ❌ なし |
| RBAC | ✅ プラグイン | ✅ 対応 | ⚠️ カスタム |
| マジックリンク | ✅ 組み込み | ✅ 対応 | ✅ 対応 |
| メール/パスワード | ✅ 組み込み | ✅ 対応 | ✅ 対応 |
| セッション管理 | ✅ JWT + DB | ✅ JWT | ✅ JWT + DB |
| TypeScript | ✅ ファーストクラス | ✅ 対応 | ✅ 対応 |
| フレームワーク対応 | ✅ 非依存 | ⚠️ React 中心 | ✅ 非依存 |
| ベンダーロックイン | ✅ なし | ❌ 強い | ✅ なし |
| カスタマイズ | ✅ 完全な制御 | ⚠️ 限定的 | ✅ 完全な制御 |
| 本番環境対応 | ✅ 対応 | ✅ 対応 | ✅ 対応 |
推奨:
- better-auth を使う場合:セルフホスト可能な構成、Cloudflare D1、完全な制御を求める場合、ベンダーロックインを避けたい場合
- Clerk を使う場合:マネージドサービスを求める場合、費用を許容できる場合、最速でセットアップしたい場合
- Auth.js を使う場合:すでに Next.js を使用している場合、基本的なニーズの場合、使い慣れている場合
ベストプラクティス
セキュリティ
- 本番環境では必ず HTTPS を使用してください(例外はありません)
- シークレットを定期的にローテーションしてください:
# Generate new secret openssl rand -base64 32 # Update in Wrangler wrangler secret put BETTER_AUTH_SECRET - サインアップ時にメールドメインを検証してください:
emailAndPassword: { enabled: true, validate: async (email) => { const blockedDomains = ['tempmail.com', 'guerrillamail.com'] const domain = email.split('@')[1] if (blockedDomains.includes(domain)) { throw new Error('Email domain not allowed') } } } - CSRF 保護を有効にしてください(better-auth ではデフォルトで有効です)
- 認証エンドポイントにレート制限を使用してください
- セキュリティ監視のために認証イベントを記録してください:
onSuccess: async (user, action) => { await logAuthEvent({ userId: user.id, action, // 'sign-in', 'sign-up', 'password-change' timestamp: new Date(), ipAddress: req.headers.get('cf-connecting-ip') }) }
パフォーマンス
-
セッション参照をキャッシュしてください(Workers では KV を使用します):
const session = await env.SESSIONS_KV.get(sessionId) if (session) return JSON.parse(session) // Fallback to DB if not in cache const dbSession = await db.query.sessions.findFirst(/* ... */) await env.SESSIONS_KV.put(sessionId, JSON.stringify(dbSession)) -
頻繁にクエリされるフィールドにインデックスを使用してください:
CREATE INDEX idx_sessions_user_id ON sessions(userId); CREATE INDEX idx_accounts_provider ON accounts(provider, providerAccountId); -
セッションデータを最小限にしてください(必須フィールドのみ)
-
認証エンドポイントにCDN を使用してください(公開ルートをキャッシュします):
// Cache GET /api/auth/session for 5 minutes c.header('Cache-Control', 'public, max-age=300')
開発ワークフロー
-
環境ごとの設定を使用してください:
const isDev = process.env.NODE_ENV === 'development' export const auth = betterAuth({ database: /* ... */, baseURL: isDev ? 'http://localhost:3000' : 'https://yourdomain.com', session: { expiresIn: isDev ? 60 * 60 * 24 * 365 // 1 year for dev : 60 * 60 * 24 * 7 // 7 days for prod } }) -
ngrok を使ってローカルでソーシャル認証をテストしてください:
ngrok http 3000 # Use ngrok URL as redirect URI in OAuth provider -
開発用にテストユーザーをシードしてください:
// seed.ts const testUsers = [ { email: '[email protected]', password: 'password123', role: 'admin' }, { email: '[email protected]', password: 'password123', role: 'user' } ] for (const user of testUsers) { await authClient.signUp.email(user) }
同梱リソース
このスキルには、以下のリファレンス実装が含まれています。
scripts/setup-d1.sh- Cloudflare Workers 用の D1 データベースを自動セットアップしますreferences/cloudflare-worker-example.ts- 認証と保護されたルートを備えた完全な Workerreferences/nextjs-api-route.ts- Next.js API ルートのパターンreferences/react-client-hooks.tsx- 認証フックを備えた React コンポーネントreferences/drizzle-schema.ts- better-auth のテーブル用 Drizzle ORM スキーマassets/auth-flow-diagram.md- OAuth とメール認証のフロー図
必要に応じて Read ツールを使い、これらのファイルにアクセスしてください。
トークン効率
このスキルを使わない場合:約15,000トークン(セットアップの試行錯誤、CORS のデバッグ、D1 アダプター、OAuth フロー) このスキルを使う場合:約4,500トークン(パターンに基づいた直接的な実装) 削減率:約70%(10,500トークン)
防止できるエラー:解決策とともに記録された、よくある問題10件
追加リソース
- 公式ドキュメント:https://better-auth.com
- GitHub:https://github.com/better-auth/better-auth
- 例:https://github.com/better-auth/better-auth/tree/main/examples
- Discord:https://discord.gg/better-auth
- 移行ガイド:https://better-auth.com/docs/migrations
バージョン互換性
テスト済みのバージョン:
[email protected]@cloudflare/workers-types@latest[email protected][email protected]- Node.js 18+, Bun 1.0+
破壊的変更:アップグレード時に変更履歴を確認してください:https://github.com/better-auth/better-auth/releases
最終確認日:2025-10-31 | スキルのバージョン:1.0.0