Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
-AIが認証し、AIが認証を書く- AI Agent 時代の認証ライブラリ Better A...
Search
Kaito.K
July 22, 2026
1.5k
6
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
-AIが認証し、AIが認証を書く- AI Agent 時代の認証ライブラリ Better Authを理解する
Kaito.K
July 22, 2026
More Decks by Kaito.K
See All by Kaito.K
Generative UI に JSONは最適か? Open UIという選択肢
sc30gsw
0
32
RPC導入_失敗の理由
sc30gsw
2
380
Featured
See All Featured
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.8k
Color Theory Basics | Prateek | Gurzu
gurzu
1
470
Into the Great Unknown - MozCon
thekraken
41
2.7k
A better future with KSS
kneath
240
18k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
840
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.1k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
730
Tell your own story through comics
letsgokoyo
1
1.1k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
330
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.6k
Optimizing for Happiness
mojombo
378
71k
Deep Space Network (abreviated)
tonyrice
0
310
Transcript
OFFERS DEEPDIVE — #Offers_DeepDive AIが認証し、AIが認証を書く AI Agent 時代の認証ライブラリ Better Authを理解する
00 — オープニング 柿 海⽃(@cu30rry_) ENECHANGE株式会社 Webアプリケーションエンジニア 業務 TypeScript 個人
TanStack Start React Hono Next.js TanStack Start ElysiaJS React Native Expo
00 — オープニング 認証基盤って結局何を選べばいいの? Better Auth です。 ※ 要件次第で他を検討 ここからは「なぜ」の積み上げ。歴史‧機能‧競合⽐較
‧AI認証の未来の順に根拠を重ねます。 前半が発表本編、後半に全詳細の Appendix。資料としてフル版を 共有します。 00 オープニング 01 Better Authとは 02 歴史 03 コア機構 04 認証⽅式 05 フレームワーク統合 06 プラグイン⼤全 07 Infrastructure 08 ⽐較 — なぜ他ではないのか 09 AI認証の未来 10 おわりに
CHAPTER 01 Better Auth — What Better Authとは 認証の2流派 /
定義と規模 / 最⼩コード
01 — Better Authとは 認証サービスの2つの流派 HOSTED SAAS SELF-HOSTED LIBRARY ホスト型
SaaS ⾃前ホスト型ライブラリ Auth0 / Clerk / Cognito / Firebase / Kinde / WorkOS Better Auth / Auth.js ユーザーデータはベンダー側に置かれる 本質は「データを誰が持つか」。 ユーザーデータは⾃分の DB に残る
01 — Better Authとは Better Auth の定義と規模 ⾃分のコードベースとデータベースの中で完結する、 TypeScript ファーストの包括的な
認証フレームワーク フレームワーク⾮依存 OSS‧MIT BYODB(⾃分のDB) ヘッドレス プラグイン拡張 470万+ 850⼈+ 2年 週間 npm ダウンロード コントリビューター 公開から買収までの期間
01 — Better Authとは auth.ts 1ファイルから始まる -/ auth.ts -/ route
handler にマウント import { betterAuth } from "better-auth"; export const { GET, POST } = toNextJsHandler(auth.handler); export const auth = betterAuth({ database: -* pg / prisma / drizzle --. -/ emailAndPassword: { enabled: true }, -/ lib/auth-client.ts socialProviders: { import { createAuthClient } from "better-auth/react"; google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret : process.env.GOOGLE_CLIENT_SECRET!, }, export const auth = createAuthClient({ -/ Auth Server の URL }, baseURL: “http:-/localhost:3000” }); }); -/ クライアントから await authClient.signIn.email({email,password });
CHAPTER 02 Better Auth — History 歴史 誕⽣ → v1.0.0
→ Auth.js 合流 → Vercel 買収
02 — 歴史 はじまりは組織(マルチテナント)対応からだった Web分析プラットフォームをNext.jsとAuth.js(旧 NextAuth)で開発している! しかし、組織(マルチテナント)機能が必要になっ た‧‧‧ 組織(マルチテナント)対応できるものでAuth.js (旧NextAuth)と連携できる認証サービスないか
な?
02 — 歴史 数週間後‧‧‧ プロジェクトに機能を組み込めた! リファクタもしたぞ! ちょうどAuth.js(旧NextAuth)が組 織サポートを追加しましたよ! でも、不満あり‧‧‧
02 — 歴史 しかし‧‧‧ Auth.js(旧NextAuth)の組織サポートしたはいい けど、開発体験悪いし、つまる‧‧‧ ExpoでAuth.js(旧NextAuth)でOAuth追加するの不可 能だし、別プロジェクトでNext.js → Svelte移⾏で
Svelte⽤のNextAuthないし、⼤変すぎる
02 — 歴史 Better Authの始まり① 認証を⾃社で管理したい! でも、必要な認証機能を ⼀つ⼀つ開発する時間はかけたくない 良いソリューションがあったらいいな〜
02 — 歴史 Better Authのはじまり② ほとんどの⼈はそういうことを考えてい るのか! “Better Auth”って名前よくないか?! npmで”Better
Auth”が利⽤可能な ら、フレームワークに依存しないプラ グインで拡張できる認証フレームワー クを作ることにしよう!
02 — 歴史 運命の⽇ https://x.com/bekacru/status/1838257293546123611
02 — 歴史 寝室での開発 から Vercel 買収まで — 2年のタイムライン 開発開始
アディスアベバ ⾃宅の寝室を中⼼に 開発 2024 YC X25 採択 $5M シード Auth.js 保守移管 Vercel 買収発表 GitHub 公開 GitHub API 確認済み Spring 2025 Peak XV 主導 Discussion #13252 額⾮公開‧MIT 継続 2024-09 2024-11-23 2025-06-25 2025-09 2026-07-07 v1.0.0 2025 春
02 — 歴史 Auth.js 合流、そして Vercel 買収へ 2026-07-07 — Vercel
買収発表 01 創業者とコアチームが Vercel に合流 02 Next.js + Auth.js + Better Auth — 認証レイヤーの垂直統合 03 狙い = 「アプリとAI エージェント向け OSS 認証の加速」 2025-09 — GitHub Discussion #13252 “Auth.js is now part of Better Auth” NextAuth ユーザーの進化先は事実上 Better Auth に。公式移⾏ガ イドあり。 OSS(MIT)継続を明⾔
CHAPTER 03‒07 Capabilities 機能総覧 コア機構 / 認証⽅式 / フレームワーク統合 /
プラグイン / Infrastructure — 各詳細は Appendix
03 — 機能総覧 / コア機構 コア機構 — できること総覧 機構 できること
auth.handler Web 標準の単⼀関数。catch-all ルート1本に挿すだけで全エンドポイントが動く auth.api 同じ機能をサーバー内部から型安全な関数として直接呼べる(失敗時は APIError を throw) CLI generate / migrate でスキーマ⾃動⽣成 — 認証テーブルを⼿書きしない Client React / Vue / Svelte / Solid / vanilla の5パス。useSession 購読‧{ data, error } 設計 Session Cookie ベース‧7⽇ローリング更新。1台だけ / 全部の失効 API、Redis 退避、cookieCache Cookies すべて secret で署名。compact / jwt / jwe の3⽅式‧サブドメイン共有 Hooks エンドポイント before / after + databaseHooks — プラグインを書かずに振る舞いを差し込む Rate limit 本番は既定で有効(60秒 / 100回)。パス単位の customRules User / 型安全 additionalFields でスキーマ拡張‧accountLinking‧$Infer で型がクライアントまで通る 詳細は Appendix §03 へ
04 — 機能総覧 / 認証方式 認証⽅式 — できること総覧 ⽅式 できること
導⼊ Email & Password サインアップ / イン‧メール検証‧パスワードリセット‧ 列挙攻撃対策(OWASP 準拠)‧ハッシュ差し替え(scrypt → Argon2id) emailAndPassword: { enabled: true } のみ ソーシャルログイン Google‧Apple‧GitHub‧LINE‧Kakao‧Naver など組み込み30種超。 プロフィールマッピング‧コールバック処理込み clientId / clientSecret を渡すだけ Generic OAuth OAuth 2.0 / OIDC 準拠なら何でも接続 — 社内 IdP‧Auth0‧Keycloak‧Okta‧独⾃ OAuth discoveryUrl 1⾏ or プリセットヘルパー8種 パスワードレス Magic Link(メールリンク)‧Email OTP‧ Passkey(WebAuthn / ⽣体)‧電話番号 SMS プラグイン1⾏ + スキーマ再⽣成 多要素‧その他 2FA(TOTP / OTP / バックアップコード)‧ SIWE(ウォレット署名)‧匿名ユーザー → 本登録 プラグイン1⾏ + スキーマ再⽣成 詳細は Appendix §04 へ
05 — 機能総覧 / フレームワーク統合 フレームワーク統合 — 対応総覧 Request →
auth.handler → Response — どこでもこの1本を挿すだけ カテゴリ 対応 やること フロント / フルスタック Next.js‧Nuxt‧SvelteKit‧SolidStart‧Astro‧ React Router / Remix‧TanStack Start catch-all ルート1本に公式ヘルパー バックエンド Hono‧Fastify‧Express‧Elysia‧Nitro‧NestJS‧Convex ワイルドカードルートに auth.handler モバイル / デスクトップ Expo‧Lynx‧Electron 既存サーバーを流⽤ + クライアントプラグイン ランタイム Node.js‧Deno‧Bun‧Cloudflare Workers Web 標準の Request / Response が動けば OK 詳細は Appendix §05 へ
06 — 機能総覧 / プラグイン (1/2) プラグイン総覧① — 認証‧認可‧企業 認証系(
10) 認可・承認系( 5) Two-Factor TOTP‧OTP‧バックアップコードの⼆要素認証 Admin ユーザー管理‧BAN‧なりすまし Passkey WebAuthn / ⽣体認証。フィッシング耐性 API Key キー発⾏‧検証‧レート制限 Magic Link メールリンクでパスワードレス Organization 組織‧チーム‧招待‧RBAC Email OTP コード1つでサインイン‧検証‧リセット MCP ⾃アプリを OAuth プロバイダ化 Phone Number 電話番号 + SMS OTP Agent Auth AI エージェントの識別‧認可(→ §09) Username ユーザー名でもログイン 企業系( 4) Anonymous ゲスト体験 → 後から本登録へリンク OIDC Provider ⾃社をログイン基盤にする One Tap Google ワンタップログイン OAuth Provider OIDC + MCP の後継統合 SIWE Ethereum ウォレット署名で認証 SSO 企業 IdP(SAML / OIDC)を消費 Generic OAuth 任意の OAuth2 / OIDC を追加 SCIM Okta / Entra からディレクトリ同期 詳細は Appendix §06 へ
06 — 機能総覧 / プラグイン (2/2) プラグイン総覧② — ユーティリティ‧決済 ユーティリティ(
12) 決済(7) Captcha Turnstile / reCAPTCHA でボット対策 Stripe 直接 PSP。サブスク‧Webhook ⾃動処理 JWT 外部連携⽤トークン + JWKS 検証 Polar MoR — 税を丸投げ + 特典⾃動配布 OpenAPI 全エンドポイントのリファレンス UI Autumn Stripe の上の従量‧クレジット課⾦ Multi-Session 複数アカウントの同時ログイン Dodo Payments 150+カ国のグローバル MoR Have I Been Pwned 漏洩済みパスワードを拒否 Creem MoR + 収益分配(レベニュースプリット) Bearer Token Cookie の代わりにトークン認証 Chargebee エンプラ向けサブスク管理層 Device Authorization CLI‧TV‧IoT のログイン Commet AI / API 従量課⾦の MoR OAuth Proxy プレビュー環境の redirect 問題を解消 One-Time Token クロスドメインの受け渡し Last Login Method 「前回は Google」表⽰ i18n エラー⽂⾔の多⾔語化 Test utilities 認証フローのテスト⽤ヘルパー MoR = 販売者を肩代わりし税/VAT の申告‧納税まで代⾏するモデル。導⼊ はどれも「plugins: [] に1⾏ + スキーマ再⽣成」。 詳細は Appendix §06 へ
07 — 機能総覧 / Infrastructure Infrastructure — ⼊れると何が⼿に⼊るか ⼿に⼊るもの 具体的には
プラグイン / プラン 管理画⾯ ユーザー‧組織‧セッションを GUI で検索‧BAN‧なりすまし。 統計と監査ログは⾃動収集 dash()‧無料〜 攻撃を防ぐ⼒ 総当たり‧ボット‧使い捨てメール‧トライアル悪⽤‧ 不可能移動を検知し、記録 → チャレンジ → 遮断 sentinel()‧Pro 以上 届くメール 検証‧リセット‧招待メールをテンプレート13種でマネージド配信 (SES / SendGrid / Resend) Email Service‧Pro 以上 企業要件への回答 SSO(SAML)‧SCIM ディレクトリ同期‧SIEM へのログ転送 Enterprise コア(認証機能)はどこまでも無料。有料なのは「運⽤」だけ —DB とユーザーデータは⾃前のまま。 詳細は Appendix §07 へ
CHAPTER 08 Comparison ⽐較 — なぜ他ではないのか 総合⽐較 / 各社の良い点と限界 /
正直なデメリット / 判断軸
08 — 比較 総合⽐較表 プロダクト 形態 データ所有 型安全 UI 提供
料⾦(2026前半検証‧要再確認) AI対応 Better Auth OSS ライブラリ(MIT)/ ⾃前ホスト ⾃分の DB ◎ ×(ヘッドレ ス) 無料(OSS)。運⽤は Infra(有 ◎ Agent Auth 料)で任意 Auth0 ホスト型 SaaS (Okta 傘下) ベンダー側 ◦ ◎ Universal Login 無料25K MAU → $35/mo〜‧超過 △ $0.07/MAU Clerk ホスト型 SaaS ベンダー側 ◦ ◎ プリビルト 無料50K MRU → Pro $25/mo + $0.02/MRU △ WorkOS ホスト型 SaaS (B2B 特化) ベンダー側 ◦ ◦ AuthKit AuthKit 1M MAU 無料 / SSO $125/接続/mo ◦ auth.md Kinde ホスト型 SaaS (認証+課⾦+フラグ) ベンダー側 ◦ ◦ 無料10.5K MAU → Pro $25/mo〜 △ Supabase Auth BaaS ⼀体型(GoTrue) Supabase 内 ◦ △ プラン内(Free 50K MAU / Pro $25/mo〜) OpenAuth OSS 認証サーバ / ⾃前ホスト ⾃分の DB ◦ × 無料(OSS)。運⽤コスト⾃⼰負 △ 担 Auth.js OSS ライブラリ / ⾃前ホスト ⾃分の DB ◦ × 無料(保守は Better Auth チーム △ へ移管済み) ※ 価格は 2026-07 検証‧登壇直前に要再確認。Clerk は MRU(retained users)、他社は MAU と課⾦単位が異なる。 △
08 — 比較 なぜ他ではないのか — 総集編 競合 良い点 でも Auth0
業界標準。エンタープライズ実績は随⼀ データはベンダー側。MAU 従量(超過 $0.07/MAU)でスケール時に⾼ 額化 Clerk プリビルト UI で導⼊最速。B2C 定番 セッション‧署名鍵‧ユーザーレコードを⾃分で所有できない WorkOS エンプラ SSO / SCIM の王者 B2B 特化でスタック委譲が前提 Kinde 認証 + 課⾦ + フラグの統合 ロックイン構造は Clerk と同型 Supabase Auth Supabase 使いなら⾃然な選択 BaaS 密結合(GoTrue)— 認証だけ切り出せない OpenAuth 同じ OSS‧セルフホスト思想 認証サーバーを別に⽴てる思想。プラグイン級の網羅なし 各社の詳細⽐較は Appendix §08 へ。
08 — 比較 / 訂正欄 デメリット 主要な注意点 小さめの注意点 1 歴史が浅い
— まだまだ採⽤事例が少ない。 6 コミュニティプラグインの品質ばらつき — 本番採⽤前にメンテ状 況‧中⾝を⾃分の⽬で。 2 破壊的変更リスク — 進化が速い分 API が動く。バージョン固定 + 検証環境で先に試 す。 7 TS/Node‧RDB 前提が強い — ⾮ TS‧NoSQL は⼀級市⺠ではな い。スタックが外れるなら他も⽐較。 3 ⾃前ホスト = 運⽤責任は⾃分 — メール‧スケール‧パッチ‧セキュリティなど全て が⾃分の責務。⾃由の代償。 4 プラグイン追従の⼿間 — 追加のたび generate / migrate。1つずつ⾜して都度確認が 安全。 5 Infrastructure(有料)依存の芽 — 寄せすぎるとロックインとなる(→ 7-11)。線 引きは設計段階で必要。 弱点の多くは「新しい OSS」「⾃前ホスト」の裏返し。データ所有 ‧型安全‧網羅性‧AI ネイティブがコストを上回るか — その⼀点 で判断する。
08 — 比較 判断軸のまとめ データ⾃社 + TS フルスタック Better Auth
50K MAU 未満の B2C を最速で Clerk も合理的 エンタープライズ SSO 最優先 WorkOS も合理的 それでも答えは Better Auth — 型安全‧データ所有‧網羅、そして第9章。
CHAPTER — 山場 09 AI & Auth AI認証の未来 AI が認証を「書く」/
AI が認証「される」— 2軸で読む
09 — AI認証の未来 あなたのアプリを使うのは、もう⼈間だけじゃない 57.5% 20% 970倍 Web トラフィックの過半が bot
に — 史上 初の逆転 Cyber Week の全注⽂の2割に AI が関与 MCP SDK の⽉間 DL — 18か⽉で10万 → 9,700万 主因は agentic AI。Cloudflare Radar(2026-06) AI 経由流⼊は前年⽐ +393%‧CV 約42%⾼。 Salesforce / Adobe(2025-12〜2026 Q1) 公開 MCP サーバーは1万超。Anthropic (2025-12〜2026-03) 利⽤者に AI が加わった。では、その AI をどう受け⼊れる? ※ Gartner 予測: 2028年に B2B 購買の90%が AI エージェント経由($15兆)
09 — AI認証の未来 2軸フレーム — 「AIと認証」の2つの向き AXIS 1 AXIS 2
軸① AI が認証を書く 軸② AI が認証される 問い AI に実装させられるか 問い エージェント⾃⾝を受け⼊れ、認証できるか 主役 開発者 + コーディング AI 主役 AI エージェント 答え CLI‧MCP‧Skills‧llms.txt‧Ask AI 答え Agent Auth‧auth.md ⇄ Better Auth = 実装の⾃動化 = 認証される主体の追加 SaaS は軸①でブラックボックス化しがち。Better Auth はコードベース型 OSS を武器に両軸を同時に押さえる。
09 — 軸② AI が認証する 既存の認証は「⼈間 + 静的アプリ」しか想定していない エージェントは短命タスクから常駐ワーカー、多段の⾃律システム ま
で幅がある。 既存モデル(OAuth・セッション・API キー) ⼈間のユーザー 静的アプリ 事前定義スコー プ AI エージェント = 第3のアクター(モデルの外側) ⼈間の介在なしに、ユーザーの代理で、時に⾃分の判断 で外部サービ スを呼ぶ。 — ⼈間でも静的アプリでもない。既存の認証モデルにそのまま当ては まらない。
09 — 軸② AI が認証する 問題 — Delegated Agents(継承された identity)
ユーザーの鍵 1本 (OAuth トークンやAPI キー) �� 可視性なし どのエージェントのリクエストか判別できない ↓ ユーザーの全権限を全員で共有 🤖 🤖 🤖 Agent A Agent B Agent C スコープなし 資格情報を共有する全エージェントが同じ権限 分離なし 1体だけ失効できない サーバーからは全部「同じユーザー」に⾒える — ⽌めるなら全停⽌しかない = 監査不可‧最⼩権限が効かない‧事故時の封じ込め不可。
09 — 軸② AI が認証する Agent Auth Protocol(v1.0-draft)— 独⽴ principal
化 Agent はユーザーの権限を借りるシステムに存在しない主体から、システムの登場⼈物として識別されるようになる AI エージェントの認証‧capability ベース(できること単位ベースの)認可 ‧サービス発⾒(Agentが訪問したシステムについて⾃⼒で理解す る仕組み)のオープンな標準仕様を提供 + Better Auth側でSDK(エージェント‧サーバー側の実装)およびPluginが提供されている、という実 装⾯もカバー。identity 継承の代わりに、各エージェントが固有の以下4つを持つ �� identity どのエージェントかをサーバーが識別できる固有の⾝元 暗号鍵ペア エージェント⾃⾝の鍵。リクエストへの署名に使う identity scoped capabilities 最⼩権限で絞れる範囲付きの能⼒ 鍵ペア 独⽴ライフサイクル そのエージェントだけを発⾏‧更新‧失効できる 1エージェント = 1バッジ capabilities ライフサイクル
09 — 軸② AI が認証する 3つの⽋落は、こう解消される 可視性なし → 🤖 🤖
🤖 Agent A Agent B Agent C 🔑 ⾃分の鍵 🔑 ⾃分の鍵 🔑 ⾃分の鍵 notes:read deploy:run pay:limit ⏻ 個別失効 ⏻ 個別失効 ⏻ 個別失効 固有 identity で clear attribution どの⾏為を誰(どのエージェント)がやったか、 明確に帰属させられる) スコープなし → エージェントごとに capability(できること) 付与(least privilege) 分離なし → 独⽴ライフサイクルで個別失効 結果: Claude / ChatGPT / Cursor のようなアプリが銀⾏‧API‧デプロイパイ プラインへ、帰属明確 + 権限最⼩でタスク実⾏できる。
09 — 軸② AI が認証する 仕様の範囲と3つの役割 SPECIFICATION — 7項目 identity
capabilities lifecycle registration approval Servers 認可と capability 管理を⾏う側 Client エージェントとサーバーをつなぐブリッジ Agents 実⾏時の AI アクター本体 authentication discovery
09 — 軸② AI が認証する フロー — discovery → registration
→ capability authorization 1 Agent → Server GET /.well-known/agent-configuration → capabilities ⼀覧を取得 2 Agent capabilities を⾒て「何が必要か」を判断 3 Agent → Server register + capability grant をリクエスト 4 Server ⇄ User(承認) device_authorization(ユーザーコードのブラウザ承認)or ciba (バックチャネル)→ capability grant 発⾏ 5 Agent → Server 短命 JWT(aud = 呼び先 URL)に署名し、default_location(または capability 個別の location)で実⾏ ※ base path が /api/auth でも、発⾒ルートは /.well-known/agent-configuration に置く。
09 — 軸② AI が認証する 従来⼿法との⽐較 観点 OAuth API キー
Delegated(継承) Agent Auth エージェント識別 不可(アプリ単位) 不可(キー単位) 不可(溶け込む) 可(principal ごと) 権限の粒度 事前定義スコープ キーに紐づく固定 共有 = 同⼀権限 capability 個別付与 個別失効 困難 キー失効で全停⽌ 不可 可(独⽴ライフサイクル) ライフサイクル概念 弱い なし なし あり(仕様の⼀部) FAQ「OAuth の置き換え?」→ No。別問題を解く。併存できる。
09 — 軸② AI が認証する MCP との関係 — 「MCP の
auth で⾜りる?」→ No MCP の OAuth 2.1 だけの場合 �� �� �� ↓ 潰れる MCP + Agent Auth 併存 �� �� �� A B C ↓ 個別に⾒える サーバーには「1クライアント」にしか⾒えない capability は MCP ツールとして公開、identity と認可は Agent Auth per-agent identity‧capability 認可‧ライフサイクル概念を持たな い。 層が違うから併存できる — MCP はツール提供、Agent Auth は「誰が ‧何を許されているか」。
09 — 軸② AI が認証する エコシステムと⽴ち位置 保守は Better Auth チーム。ただし
Better Auth ⾮依存 — 任意のプラットフォームが独⽴採⽤できるオープン標準。 SDK Directory Community Demo /docs/sdks agent-auth.directory Discord /demo
09 — 軸② AI が認証する Better Auth の agent-auth プラグインが実装するもの
✓ identity‧registration‧discovery‧capability 認可を公式プラ グインとして組み込み済み ✓ /.well-known/agent-configuration ルートを⽣やす ✓ 承認⽅式 device_authorization / ciba をサポート -/ app/.well-known/agent-configuration/route.ts import { auth } from "@/lib/auth"; import { NextResponse } from "next/server"; export async function GET() { -/ プラグインが組み立てた設定を返すだけ const config = await auth.api.getAgentConfiguration(); ✓ 短命 JWT(aud ⼀致)署名で capability 呼び出し 2軸の交差点 : 軸①の CLI / プラグイン体験の上に、軸②の「AI が認証さ れる」機能が乗る。 return } NextResponse.json(config);
09 — 軸② AI が認証する / auth.md AUTH.md とは —
WorkOSがlaunchしたエージェント向けの「会員登録案内」 robots.txt クローラーに「巡回のルール」を伝えるテキスト llms.txt LLM に「⽂書の索引」を渡すテキスト AUTH.md AI エージェントに「このサービスへの登録⼿順書」を渡すテキスト どこに置く? つまり? サービスのルート直下 — https:-/service.example.com/auth.md 。 エージェントは docs‧SDK‧401 レスポンスの WWW-Authenticate ヘッダ から「⼈間と同じように」発⾒する サインアップフォーム(⼈間の UI)の代わりに、「エージェントが読める 登録の契約書」をドメインに置く発想 注意 中⾝は? 番号付きの⼿順書: 発⾒ → ⽅式選択 → 登録 → claim → トークン交換 → 利 ⽤ → 失効対応。コードブロックはそのままリクエストのテンプレートとし て抽出される 正式な情報源は PRM(/.well-known/oauth-protected-resource)— auth.md はそれを⼈間にもエージェントにも読める形にした補⾜資料。⽭ 盾したら PRM が正
09 — 軸② AI が認証する / auth.md AUTH.md— ドメインに置く1枚の Markdown
狙い = 「サインアップフォーム(⼈間の UI)なしでエージェントがユーザーを登録する」。典型は https:-/service.example.com/auth.md。 # auth.md — Notes App -# Supported flows - agent-verified # IdP が保証 - user-claimed # ユーザーがコードで確認 -# Scopes - notes:read - notes:write ノートの閲覧 ノートの作成・編集 -# Registration - discovery: .well-known/oauth-authorization-server identity endpoint: POST /agent/identity - token endpoint: POST /oauth2/token (jwt-bearer) -# After registration - access_token を Bearer で付与。失効時は再登録 → ⼈間の統合担当者が読むドキュメント AUTH.md エージェントが実⾏時に発⾒して読むランタイ → ム成果物 記述4点: 対応フロー / 公開スコープ / 登録⼿順 / 登録後の動作。プ レーンテキストだから両⽅に効く。
09 — 軸② AI が認証される / auth.md auth.md に書いてあること —
4節総覧 節 何を書くか ⼈間の世界で⾔うと Supported flows どの登録⽅式を受けるかの宣⾔(verified / claimed / 両対 店頭の「使える⽀払い⽅法: カード / QR」の掲⽰ 応) Scopes サービスが公開する権限メニュー(notes:read / 会員種別ごとの「できること」⼀覧 notes:write)。エージェントは必要な分だけ申請し、トー クンはその範囲に限定 Registration 登録⼿続きの窓⼝ URL ⼀覧(discovery / identity / token — 仕様上は claim‧events‧revocation 含め6窓⼝) After registration 登録完了後のトークンの使い⽅と運⽤ルール(Bearer 付与 会員証の利⽤規約 ‧失効時は再登録) 「新規登録はこちら」ボタンの機械可読版 ※ 登場⼈物は最⼤3役(Agent / Agent Provider / Service)— verified では IdP(Provider)が⾝元保証に⼊り、claimed では⼈間の確認で代替する。
09 — 軸② AI が認証される / auth.md たとえで掴む — 店員「きみ、誰?」
ロボット(エージェント)に「ノートアプリに私のメモを保存して」と頼んだ。ロボットが店に着くと、店員に⽌められる — 「 本当にこの⼈の 使いなの?証明できる? 」。証明のやり⽅が2つある、というだけの話。 AGENT-VERIFIED 「⾝分証を⾒せる」 ロボットを動かしているアプリ(親元 = IdP)が「この者は本⼈の使 いです」と書いた⾝分証を発⾏し、偽造できないハンコ(電⼦署 名)を押す。店員はハンコを照合して通す。 本⼈は店に⾏かなくていい — 事前に「押していいよ」(consent)と 伝えてあるだけ。 ⾝分証 = ID-JAG / 照合 = JWKS 検証 USER-CLAIMED 「本⼈がその場で引き取る」 ⾝分証がない場合。店員「番号札 XK7 を渡すから本⼈に確認させ て」→ 本⼈が⾃分のアカウントでログインし(ログインできる = 本 ⼈の証明)「この番号のロボットは私の使いです」とボタンを押 す。 gh auth login のデバイス認証と同じ体験。 親元(IdP)不要‧毎回ワ ンタップ 違いは⼀⾏ — 「⾝分証を⾒せる」か「本⼈に確認する」か。もらえる⼊店証(トークン)は同じもの。
09 — 軸② AI が認証される / auth.md 3つの役割と ID-JAG Agent
Agent Provider(IdP) ユーザーの代理 ID-JAG を発⾏ ID-JAG = Identity Assertion JWT Authorization Grant ⾝元アサーションを認可グラントとして使う仕組み。IETF OAuth ド ラフト draft-ietf-oauth-identity-assertion-authz-grant に 基づく。 ⇄ ID-JAG ⇄ Service assertion を受理し scoped アクセスを発⾏ ID-JAG(署名付き⾝元保証書) → 交換 → scoped access_token(これが利⽤券) → Service の API を利⽤ ※ ID-JAG は利⽤券ではなく「引換の⼿前の⾝元保証書」— サインアップ画⾯なしで登録‧トークン発⾏まで進むための証明。
09 — 軸② AI が認証される / auth.md ID-JAG — 実印つきの「紹介状」
普通は窓⼝(= ログイン画⾯)で申込書を書く。ID-JAG は、信頼する銀⾏が発⾏した実印つき紹介状を持ってくれば、申込書なしで会員証を発 ⾏する。紹介状には宛先(audience)が書いてあるから、別の店では使い回せないようになっている 👤 User(あなた) 事前に⼀回だけ承諾 ① consent 「紹介状を書いていいよ」 🏦 ② 実印つき紹介状を発⾏ = ID-JAG Agent Provider (信頼する銀⾏) 🤖 ③ 紹介状を提出 POST /agent/identity 🏪 Agent 店(Service) 紹介状を携えて店(Service)へ ④ JWKS(銀⾏(Provider) の公開鍵) で 実印を照合 → ⑤ 会員証(トークン)発⾏ エージェントの所属元 (IdP) 📜 紹介状(ID-JAG) =「この者は本⼈の代理です」+ 実印(Providerのハンコ) + 宛先 (audience) → 引換 → 🎫 会員証(scoped access_token) 紹介状には宛先が書いてあるから、別の店では使い回せない(audience 固有)。紹介状 ≠ 会員証 ― 引換の⼿前の証明書
09 — 軸② AI が認証される / auth.md Agent verified flow
— IdP がユーザーを保証(8段階) 1〜3 発⾒(401 を起点に⾃⼒で探る) 4〜5 保証書の⼊⼿(consent → ID-JAG) 6〜8 提出‧検証‧交換 1 Agent → Service GET /api/resource → 401 WWW-Authenticate(resource_metadata) 2 Agent → Service GET .well-known/oauth-protected-resource → PRM(authorization_servers) 3 Agent → Service GET .well-known/oauth-authorization-server → AS metadata(agent_auth ブロック) 4 Agent ⇄ User consent —「この audience に identity を主張してよいか」 5 Agent → Provider audience 固有の ID-JAG を要求 → 発⾏ 6 Agent → Service POST /agent/identity(type: identity_assertion, assertion: ID-JAG) 7 Service → Provider GET .well-known/jwks.json — Provider の JWKS で署名検証 8 Agent → Service POST /oauth2/token(grant_type=jwt-bearer)→ scoped / short-lived / revocable な access_token ※ ⼈間が出るのはステップ4の consent ⼀回だけ — 委任状にハンコを押したら、あとは全部機械同⼠。実仕様では 6 の提出後に Service が⾃前署名の identity_assertion を返し、それを 8 で access_token に交換する⼆段交換。
09 — 軸② AI が認証する / auth.md User claimed flow
— IdP 不要、ユーザーがコードで確認 auth.md の情報だけでエージェントが⾃⼰ナビゲートできる(エージェント側の特別な統合が不要)。 1 auth.md を取得し claimed フローを選択 4 ユーザーがサインインしコードを claim → → 2 登録要求 → 確認コードを受領 5 scoped access_token に交換 → → 3 ユーザーにコード + サインイン URL を提⽰ 6 API 呼び出し。revoke 時は再登録
09 — 軸② AI が認証される / auth.md verified vs claimed
— どう使い分けるか agent-verified(8段階) user-claimed(6段階) 本⼈性の保証 ID-JAG(IdP の署名) ⼈間のサインイン + コード確認 Provider(IdP) 必要 不要 — ⼈間の確認で代替 署名検証(JWKS) Service が実施 なし ⼈間の登場 事前の consent ⼀回だけ(委任状のハンコ) 毎回の登録で動線の真ん中に登場 エージェント側の実装 IdP との統合実装が必要 auth.md を読むだけで⾃⼰ナビゲート 最終成果物 scoped access_token scoped access_token(同じ) 向いている場⾯ スケールする — ⼤量エージェントの⾃動‧組織的運⽤ ⼿軽 — 個⼈が⾃分のエージェントを1体つなぐ どちらを受けるか(verified だけ / claimed だけ / 両対応)はサービス側が Supported flows で宣⾔する — 店頭の「使える⽀払い⽅法」の掲⽰。
09 — 軸② AI が認証される / auth.md 発⾒の2パターン — どこから⼿順に⼊るか
パターン B — 先読み パターン A — 主経路 先に auth.md を読んでから⾏く まず API を叩いて、ぶつかる GET /api/resource(トークン無し) → 401 + WWW-Authenticate ヘッダに「認証⽅法はここを読め」のヒン ト → ヒントを辿って auth.md / .well-known を読み、Step 1 から進む ⾨前払いは正常動作 — 「ぶつかってから案内所に来る」が標準の旅程。 「このサービスと連携して」と頼まれ、まだ API を叩いていない(= 401 を持っていない) → 慣例パス /.well-known/oauth-protected-resource を直接 取得(仕様が明記) → 同じ⼿順に合流。登録完了までは API を叩かない スキップされるのは「401 を⾷らう体験」だけ — discovery ⾃体は必 ず踏む("do not skip ahead")。 どちらも Step 2 以降(register → 保証 → exchange)は完全に同⼀。
09 — 軸② AI が認証される / auth.md エージェントが読む6段階の⼿続きレシピ discover →
register → claim → exchange → use → handle revoke ↺ revoke を受けたら discover へ戻る discover = auth.md + .well-known を取得 / register‧claim = verified or claimed で登録‧確認 / exchange = scoped access_token に交換 use = Bearer で API 呼び出し / handle revoke = 失 効で停⽌‧再登録。定義元は workos/auth.md の AUTH.md(skill manifest) ※ 運⽤中に 401 → まず exchange(トークン再交換)を1回試す → だめなら discover からやり直し。refresh_token は存在せず、この2段が代替。⼿順は 「Follow the steps in order; do not skip ahead」— auth.md を先に読んだ場合も discovery は省略しない。
09 — 軸② AI が認証される / auth.md 信頼 / セキュリティモデル
短命 scoped audience 固有 ✓ 資格情報 = ユーザーに紐づく scoped access token。 標準 OAuth で 発⾏ (既存 API 認証を再利⽤) ✓ verified では Provider の JWKS で ID-JAG 署名を検証。アサーショ ンは audience 固有で 使い回し不可 (audience = トークンの「宛 先」。宛先限定発⾏なので他所では無効) 失効可能 ✓ consent が明⽰的に挟まる。Provider は失効イベントを送れる ✓ どのフローを受けるか(verified / claimed / 両⽅)も、発⾏する資 格情報も アプリ側が主導権
09 — 軸② AI が認証する / auth.md github.com/workos/auth.md — 仕様本体
+ 参照実装 ├── AUTH.md # skill manifest ├── agent-services/ # resource + authz server 読み⼿別の⼊⼝ ├── agent-providers/ # ID-JAG 発行のサンプル IdP → エージェント実装者 → AUTH.md(⼿続きレシピ) └── shared/ # 共有パッケージ → サービス実装者 → agent-services/README(実装ガイド‧シーケン ス図‧エラー表) → IdP 実装者 → agent-providers/README(ID-JAG 発⾏‧JWKS 公開‧ 失効イベント) WorkOS 製だが仕様はオープン。
09 — 軸② AI が認証する Agent Auth と AUTH.md の棲み分け
— 競合ではなく層が違う 観点 Agent Auth(Better Auth / AAP) AUTH.md(WorkOS) 主な問い 固有 identity をどう与えるか どう登録‧発⾒させるか 焦点 identity‧capability‧lifecycle registration(サインアップ無しの登録) 形 プロトコル + SDK + 公式プラグイン 1枚の Markdown + 参照実装 発⾒ルート /.well-known/agent-configuration auth.md + /.well-known/oauth-* 保守 Better Auth チーム WorkOS 開放性 オープン(Better Auth ⾮依存) オープン(WorkOS 著) 資格情報 暗号鍵ペア + scoped capabilities OAuth の scoped‧短命‧失効可能トークン 共通ゴール エージェントを「誰かの identity の影」から独⽴した主体へ 共通の⼟台 = OAuth / JWT / .well-known 標準
09 — 軸② AI が認証される たとえで掴むAgent Auth ProtcolとAUTH.md — パスポート
vs 会員証 AUTH.MD AGENT AUTH PROTOCOL 店ごとの会員証 パスポート エージェント本⼈が持ち歩く⾝分証。鍵ペアを⾃分で⽣成し、秘密 鍵(実印)で⾝元を証明 — どのサービスに⾏っても同じ「私はエー ジェント X」を名乗れる。 identity はエージェントに宿る。 焦点 = identity‧capability‧lifecycle ⼊店のたびにその店の台帳に登録して発⾏してもらう。店 A の会員 証は店 B で使えない(audience 固有)。verified はパスポート (ID-JAG)を⾒せて作り、claimed は本⼈が窓⼝まで同⾏して作 る。 発⾏主体はサービス側。 焦点 = registration(サインアップ無しの登 録) ※ auth.md 内も役割は2段 — ⾝元を保証するのは verified なら IdP、claimed なら⼈間の claim 操作。 トークンを発⾏するのは常に Service (保証を受けて、⾃店でだけ使える会員証を発⾏する係)。 ⾝分証の発想と、会員登録の発想 — 層が違うので競合ではなく補完。
09 — AI認証の未来 / まとめ まとめ — 認証は「⼈間の UI」から「機械が読む契約」へ ドキュメント
llms.txt 読める構造化テキストになる 認証フロー AUTH.md 発⾒‧実⾏できるランタイム成果物になる エージェントの⾝元 Agent Auth Protocol 識別‧認可‧失効できる principal になる 確定 Vercel × Better Auth の現在地 推論 ① 買収発表で「アプリとエージェント 向け OSS 認証の加速」を明⾔ (2026-07-07) eve / Passport と Better Auth の agent identity(Agent Auth プラグイン)が統合されていく⽅向が読み取れる — 具 体形は今後の発表を待つ。 ② Ship London(2026-06-17)で OSS エージェントフレームワーク eve (Apache-2.0‧"Next.js for agents")+ Vercel Passport (エージェント OIDC identity)+ Vercel Connect(OAuth トークン管理)を発表 ③ エージェント発デプロイは6か⽉で 3%未満 → 半数超(2026-06 時点) これから
CHAPTER 10 Closing おわりに まとめ / 会社紹介 / 参考⽂献
10 — おわりに 01 TS で作るなら Better Auth — 型安全‧データ所有‧プラグイン網羅。
02 Auth.js 合流と Vercel 買収で、エコシステムの中⼼に。 03 次の戦場は agent identity — その最前列に Better Auth がいる。
10 — 会社紹介 エネルギーの未来をつくる CHANGING ENERGY FOR A BETTER WORLD
エンジニア採⽤中 詳細はエンジニア採⽤サイトもご覧ください! “エネチェンジ エンジニア” で検索🔍 カジュアル⾯談申込 エンジニア採⽤サイト
10 — 参考文献 参考⽂献 — ⼀次情報 Better Auth / Vercel
エージェント認証 / その他 better-auth.com/blog/seed-round agentauthprotocol.com agent-auth.directory better-auth.com/blog/authjs-joins-better-auth github.com/better-auth/agent-auth-protocol better-auth.com/blog/better-auth-joins-vercel workos.com/auth-md github.com/workos/auth.md vercel.com/blog/vercel-acquires-better-auth datatracker.ietf.org vercel.com/blog/introducing-eve (draft-ietf-oauth-identity-assertion-authz-grant) github.com/better-auth/better-auth/releases/tag/v1.0.0 github.com/nextauthjs/next-auth/discussions/13252 ycombinator.com/companies/better-auth github.com/lucia-auth/lucia/discussions/1714 better-auth.com/docs/comparison techcrunch.com/2025/06/25/this-self-taught-ethiopian-dev-b better-auth.com/docs/ai-resources better-auth.com/llms.txt uilt-an-authentication-tool-and-got-into-yc workos.com/blog/vercel-acquires-better-auth-migrate-to-wor kos AI 利⽤統計(§9-00) radar.cloudflare.com(bot 57.5%・2026-06)/ salesforce.com/news(Cyber Week AI 関与 20%・2025-12)/ business.adobe.com(AI 経由流入 +393%・2026 Q1)/ anthropic.com(MCP サーバー1万超・2025-12)/ gartner.com(B2B 購買 90% 予測・2025-11) ご清聴ありがとうございました。#Offers_DeepDive @cu30rry_ / ENECHANGE株式会社
APPENDIX Full Reference 詳細リファレンス Appendix 歴史の各論 / コア機構‧認証⽅式‧統合‧プラグイン‧Infrastructure の全詳細 /
競合⽐較の各論 / AI が認証を「書く」開発体験 ※ 最新情報や正確な情報は公式ドキュメントを参照してください
02 — 歴史 誕⽣ — 独学の開発者が寝室から作った OSS エチオピア‧アディスアベバ出⾝の独学プログラマー Bereket Engida
を中⼼に、2024年、⾃宅の寝室で開発が 始まった。 正確に⾔うと: 「6か⽉」は開発期間ではなく、公開後に ⼈気化するまでの期間。 2024年9⽉の GitHub 公開から わずか半年で⼈気ライブラ 創業者数: 単独説(TechCrunch/YC)と共同説(Addis Insight)が併存するため断定しない。 リへ 成⻑。世界標準候補への道を駆け上がった。
02 — 歴史 買収の構図 — 認証レイヤーの垂直統合 VERCEL Next.js Auth.js(2025-09 保守移管)
Better Auth(2026-07 買収) React エコシステムの認証中核を掌握 。フレームワー クと認証が同⼀ベンダーに揃った。 WorkOS は即⽇「Better Auth ユーザーは WorkOS へ」と応 戦ブログを公開 — 業界が警戒している証拠。
02 — 歴史 OSS 認証ライブラリの明暗 — Lucia と Better Auth
OBITUARY FRONT PAGE Lucia RIP Better Auth 2025-03、v3 を⾮推奨化し開発停⽌。 同じ⾃前ホスト思想から出発し、2年で Vercel 傘下へ駆け上 がった。 「⾃前実装のための学習リソース」へ転換した。 週間 470万+ DL の⽣態系を築いた。 ↘ ↗ 教訓: 思想だけでは⽣き残れない。エコシステム‧型安全‧網羅性‧保守の持続性が分⽔嶺。
APPENDIX 03 Core Concepts コア機構 auth インスタンス / API /
CLI / Client / Database / Hooks / Session / Rate limit
03 — コア機構 全体像 — コア+プラグインの⼆層構造 Plugins 層(任意‧着脱可) twoFactor /
organization / genericOAuth / passkey … endpoints‧schema‧hooks‧rateLimit を「⾜す」 Core 層(常に存在) emailAndPassword‧socialProviders‧session‧cookies‧rateLimit‧user/a ccount‧email Database アダプタ Kysely(組込)/ Prisma / Drizzle / MongoDB ↓ auth.handler を /api/auth/* にマウント Client — createAuthClient 対のクライアントプラグインとともに叩く: signIn / useSession / twoFactor.* … -/ auth.ts — 出発点 import { betterAuth } from "better-auth"; export const auth = betterAuth({ emailAndPassword: { enabled: true }, socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret : process.env.GOOGLE_CLIENT_SECRET!, }, }, });
03 — コア機構 auth インスタンスの 4つの顔 auth.handler auth.api Web 標準の
(req) -> Promise<Response> ハンドラ。/api/auth/* を処理す 全エンドポイントをサーバー側から型安全に呼ぶための関数群。 る。 auth.$Infer auth.options Session / User などの型を推論するための型専用名前空間。 正規化済みの設定オブジェクト。
03 — コア機構 API — すべての機能はエンドポイント、呼び⽅は2経路 経路1 HTTP 経由 —
auth.handler をマウントし、クラ イアントから叩く 経路2 サーバー内部から auth.api.* を関数として直接呼 ぶ(HTTP ⾮経由で⾼速) -/ サーバー側でセッション取得 const session = await auth.api.getSession({ headers: await headers(), }); auth.api は { body, headers, query, params } を取り、戻り 値は 既定でパース済みデータ(Response ではない)。 -/ サインアップも内部呼び出しできる const res = await auth.api.signUpEmail({ body: { email: "
[email protected]
", password: "password1234", name: "Taro" , }); },
03 — コア機構 ⽣の Response / ヘッダが欲しいとき asResponse: true —
⽣の Response を返す returnHeaders: true — Set-Cookie 等を取り出す const response = await auth.api.signInEmail({ body: { const { headers, response } = await email, password }, asResponse: true , }); auth.api.signInEmail({ body: { email, password }, returnHeaders: true , }); const sc-camel-set-cookie = headers.get( "set-cookie" );
03 — コア機構 route handler への接続 — catch-all に1本 basePath
の既定は /api/auth Next.js App Router -/ app/api/auth/[--.all]/route.ts Node / Express import { toNodeHandler } from "better-auth/node" ; import { toNextJsHandler } from "better-auth/next-js" ; app.all("/api/auth-*", toNodeHandler(auth)); -/ 注意: express.json() より前にマウント -/ (body を奪わ export const { GET, POST } = toNextJsHandler(auth.handler); れないため)
03 — コア機構 エラーハンドリングの⾮対称性 auth.api.* authClient.* 失敗時に APIError を throw
throw せず { data, error } を返す サーバー内部呼び出しは try/catch で受ける。 error.code で分岐する Result 型スタイル。 この⾮対称を必ず押さえる。
03 — コア機構 CLI — generate / migrate / init
/ secret(+ info / mcp) generate アダプタに応じたスキーマ/マイグレーションを⽣成 # スキーマ生成(ORM は各自のツールで適用) npx @better-auth/cli@latest generate migrate DB に直接適⽤(Kysely 組み込みアダプタ限定) init 初期セットアップ # Kysely 組み込みのみ DB 直接適用 secret BETTER_AUTH_SECRET ⽤キー⽣成 npx @better-auth/cli@latest init info 環境‧設定の診断情報(issue 報告⽤) mcp エディタ向け MCP サーバー設定を書き出し 外部 ORM(Prisma / Drizzle / MongoDB)は migrate 不可 → generate 後に ORM ⾃⾝のマイグレーションツールで適⽤。 npx @better-auth/cli@latest migrate npx @better-auth/cli@latest secret # エディタ AI に文脈を渡す npx @better-auth/cli mcp --cursor
03 — コア機構 Client — インポートパスでフレームワークを切り替える better-auth/react React(useSession は hook)
better-auth/vue Vue(リアクティブな ref / store) better-auth/svelte Svelte(store) better-auth/solid Solid(signal) better-auth/client フレームワーク⾮依存(vanilla) -/ lib/auth-client.ts (React) import { createAuthClient } from "better-auth/react"; export const sc-camel-auth-client = createAuthClient({ baseURL: "http:-/localhost:3000" , });
03 — コア機構 主要なクライアントメソッド -/ サインアップ(email/password)。email・password・name が必須 const { data,
error } = await authClient.signUp.email( { email: "
[email protected]
", password: "password", name: "User" , } ); -/ サインイン(email/password) await authClient.signIn.email({ email, password }); -/ ソーシャルサインイン(OAuth リダイレクト開始) await authClient.signIn.social({ provider: "google", callbackURL: "/dashboard" }); -/ サインアウト await authClient.signOut(); throw せず { data, error } を返す — error.code で分岐。
03 — コア機構 セッションの参照 — useSession と getSession useSession —
リアクティブに購読 export function UserButton() { const { data : session, isPending, error } = const { data: session } = await authClient.getSession(); authClient.useSession(); if (isPending) return <span>--.-/span>; return } getSession — ⼀度だけ取得 <span>{session-.user.name}-/span>; React では hook、Vue / Svelte / Solid では各フレームワークのリアク ティブ‧プリミティブを返す。
03 — コア機構 セッションの失効 API — 複数デバイス管理 -/ アクティブなセッション一覧 const
{ data: sessions } = await authClient.listSessions(); -/ 特定のセッションを失効(token を指定) await authClient.revokeSession({ token : sessions[0].token 1台だけ失効 revokeSession({ token }) }); -/ 現在のセッション以外をすべて失効 await authClient.revokeOtherSessions(); -/ すべてのセッションを失効 await authClient.revokeSessions(); 現在以外を全部失効 revokeOtherSessions() 全部失効 revokeSessions()
03 — コア機構 Database — コアスキーマとアダプタ2⽅式 user session account verification
① 組み込み Kysely — ドライバ直結(migrate 可) import { Pool } from "pg"; ← 既定4モデル。プラグインが独⾃モデルを追加する ② ORM アダプタ — generate で出⼒ import { prismaAdapter } from "better-auth/adapters/prisma" ; export const auth = betterAuth({ database: new Pool({ connectionString : process.env.DATABASE_URL, }), }); const prisma = new PrismaClient(); export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: "postgresql" , }), });
03 — コア機構 Database 詳解 — 内部は Kysely 「Kysely が対応する
DB はそのまま動く」— ⽅⾔差は Better Auth 側が吸収する。 サーバーレス Neon / AWS RDS Data API エッジ Cloudflare D1 / Turso ⼤規模 MySQL PlanetScale(Vitess‧無停⽌スキーマ変更) エンタープライズ MS SQL(tedious + tarn で MssqlDialect) 迷ったら PostgreSQL — 実績‧ドキュメントが最も厚い database: new Pool({ connectionString: "postgres:-/--." , }) ※ BigQuery / ClickHouse(OLAP)は認証ストアに⾮典型 — 分析⽤途のみ。主要 DB 20種 の詳細は docs 05-database 参照。 DB なしのステートレスセッション(JWT)構成も可能。
03 — コア機構 アダプタの選び分け — 4系統 アダプタ 性質 スキーマ管理 向いているケース
組み込み Kysely ドライバ直結‧最軽量 CLI migrate で直接適⽤ ORM を⼊れたくない Drizzle 型安全‧軽量‧SQL 寄り generate 後は drizzle-kit 運⽤ 既に Drizzle 採⽤ Prisma スキーマ駆動‧ツール充実 generate で Prisma スキーマ⽣成(Prisma 7+ 既に Prisma 採⽤ / 広範な DB は output パス必須) MongoDB NoSQL ドキュメント スキーマレス(migrate/generate 不要)。 join は 1.4.0+ experimental.joins: true drizzleAdapter(db, { provider: "sqlite", schema: { --.schema, user : schema.users }, }) -/ usePlural: true も可 プラグイン追加‧変更のたびに migrate / generate を再実⾏。 ドキュメント指向 / 既存 Mongo const db = client.db(); mongodbAdapter(db)
03 — コア機構 modelName の罠 — テーブル名ではない modelNameは「アダプタが解決するモデル名 」。Prisma では
Prisma モデル名にマップされ、実テーブル名は @@map など ORM 側の責務。Kysely 直結時のみ実テーブル名と⼀致する。 export const auth = betterAuth({ user: { -/ アダプタのモデル名 modelName: "users", fields: { -/ カラム名のリネーム name: "full_name", email: "email_address" , }, }, session: { modelName: "user_sessions", fields: { userId: "user_id" }, }, }); 設定 — modelName: "users" ↓ アダプタのモデル名(Prisma ならモデル名) ↓ 物理テーブル名(@@map 等 ORM の責務)
03 — コア機構 User 設定 — additionalFields / changeEmail /
deleteUser user: { additionalFields: { role: { type: ["user", "admin"], defaultValue: "user", -/ クライアントから渡させない input: false , }, lang: { type: "string", defaultValue: "en" }, }, changeEmail: { -/ 既定は無効 enabled: true, sendChangeEmailVerification: async ({ user, newEmail, url }) -> { --. }, }, deleteUser: { enabled: true, sendDeleteAccountVerification: async ({ user, url }) -> { --. }, }, } additionalFields type / required / defaultValue / input でスキーマ拡張。input: false は role 等「登録時にユーザー⼊⼒させない」フィールド に。 changeEmail 既定で無効。検証メールを送って変更を確定。 deleteUser 検証付き退会フロー → authClient.deleteUser({ token }) で確 定。
03 — コア機構 型安全 — $Infer とクライアントへの型ブリッジ クライアント: inferAdditionalFields サーバー:
auth.$Infer import { inferAdditionalFields } from "better-auth/client/plugins"; type Session = typeof auth.$Infer.Session; -/ additionalFields も 自動反映 -/ Session["user"]["role"] が型に乗 る → 型ブリッジ import type { auth } from "~/auth"; export const sc-camel-auth-client = createAuthClient({ plugins: [inferAdditionalFields<typeof }); 別リポジトリなら inferAdditionalFields({ user: {--.} }) でフィールド定義を⼿渡しする。 auth>()],
03 — コア機構 Email / Mail — 設定の置き場所が違う 送信⼿段はユーザー実装。Better Auth
は「いつ‧どんな URL / トークンで送るか」を組み⽴てて渡す。 メール検証 = emailVerification emailVerification: { sendOnSignUp: true, sendOnSignIn: true, autoSignInAfterVerification: true, sendVerificationEmail: async ({ user, url, token }) -> { await sendMail({ to: user.email, body : url }); }, afterEmailVerification: async (user) -> { -* 副作用 -/ }, } 検証と リセットで設定の置き場所が違う点に注意。 パスワードリセット = emailAndPassword emailAndPassword: { enabled: true, revokeSessionsOnPasswordReset: true, sendResetPassword: async ({ user, url, token }) -> { await sendMail({ to: user.email, body : url }); } },
03 — コア機構 Plugins — サーバーとクライアントの「対」構造 クライアント側 — better-auth/client/plugins サーバー側
— better-auth/plugins import { twoFactorClient } from "better-auth/client/plugins"; import { twoFactor } from "better-auth/plugins"; export const auth = betterAuth({ plugins : [twoFactor()], }); ⇄ export const sc-camel-auth-client = ペア }); -/ → authClient.twoFactor.* が型安全に生える createAuthClient({ plugins : [twoFactorClient()], endpoints‧schema‧hooks‧rateLimit ルールを追加 対応アクション‧ストアを authClient に追加 サーバーに⾜したらクライアントにも⾜す。専⽤パス import でツリーシェイク。
03 — コア機構 OAuth — 2つの経路 ① socialProviders(組み込み) ② genericOAuth
プラグイン 主要プロバイダは clientId / clientSecret を渡すだけ。 組み込みにないプロバイダはエンドポイントを⼿動指定して 接続(社内 IdP‧Keycloak 等)。 socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret : process.env.GOOGLE_CLIENT_SECRET!, }, } → 詳細は第4章で。
03 — コア機構 account linking — アカウント連携は既定で有効 account: { accountLinking:
{ enabled: true, 1⼈の user に複数の account(認証⽅式‧プロバイダ)が紐 付く。プロバイダが email verified を返せば既存ユーザーに 別プロバイダを紐付けられる。 trustedProviders: ["google", "github"], allowDifferentEmails: true , }, } allowDifferentEmails: true は「別 email を返すプロバ イダ」も連携対象にする — 乗っ取りリスクとのトレードオフ 。
03 — コア機構 Cookies — 署名と cookieCache の3⽅式 すべての Cookie
はsecretで署名される。 session.cookieCache でセッションを Cookie 側にキャッ シュし、毎回の DB アクセスを削減。 compact 既定。コンパクトな署名付き表現 jwt JWT 形式 jwe 暗号化された JWE 形式 session: { cookieCache: { enabled: true, -/ 5分キャッシュ maxAge: 5 * 60, strategy: "compact" , }, }
03 — コア機構 Cookies — セキュア属性とドメイン共有 advanced: { -/ 本番では既定で有効
useSecureCookies useSecureCookies: true, Secure 属性で HTTPS 限定。本番では既定で有効。 crossSubDomainCookies: { enabled: true, domain: "example.com" , }, cookiePrefix: "my-app" , } crossSubDomainCookies app.example.com と auth.example.com でセッション Cookie を共有。 cookiePrefix / advanced.cookies Cookie 名や個別属性(sameSite 等)をカスタマイズ。
03 — コア機構 Hooks① エンドポイント hooks(before / after) before →
本処理 → after 各1つの createAuthMiddleware を受け、ctx.path で分岐 -/ before: body 書き換え・中断 before: createAuthMiddleware(async (ctx) -> { if (ctx.path --= "/sign-up/email") { if (!ctx.body-.email.endsWith("@example.com")) { throw new APIError("BAD_REQUEST" ,{ message: "社内メールのみ許可" }); } return { context: { --.ctx, body: { --.ctx.body, name: "Default" } } }; } }), -/ after: レスポンス後の副作用 after: createAuthMiddleware(async (ctx) -> { if (ctx.path.startsWith("/sign-in")) { const session = ctx.context.returned; -/ 監査ログ送信など } }), -/ ctx.context.session = 現在のセッション -/ before の書き換えは後段に伝播する
03 — コア機構 Hooks② databaseHooks — DB レコードに割り込む databaseHooks: {
user: { create: { before: async (user, ctx) -> { if (user.isAgreedToTerms --= false) { throw new APIError("BAD_REQUEST" ,{ message: "規約同意が必要です" }); } } return { data: { --.user, role: "user" }, after: async (user, ctx) -> { -/ ウェルカムメール等の副作用 }, }, }, } }; user / session / accountのcreate / update ×before / afterをフック。 before が false → 操作を中断。{ data } → ペイロードを差し替 え。after = 成功後の副作⽤。
03 — コア機構 Session — 有効期限とローリング更新 session: { -/ 7日
expiresIn: 60 * 60 * 24 * 7, -/ 1日ごとに延長 利⽤なし 7⽇で失効 updateAge: 60 * 60 * 24 , } 利⽤あり(ローリング) 失効線が先へスライド セッションが使われ、かつ updateAge(既定1⽇)に達すると、失 効時刻が「現在 + expiresIn」へ更新される。
03 — コア機構 Session — secondaryStorage と保存先の分岐 -/ Redis 等に逃がす3関数
secondaryStorage: { get: async (key) -> await redis.get(key), set: async (key, value, ttl) -> await redis.set(key, value, "EX", ttl), delete: async (key) -> await redis.del(key), secondaryStorage あり? } Yes → Redis / KV に保存(storeSessionInDatabase: true で主 DB 併 存) / No → 主 DB の session テーブル -/ 主 DB なし + 短命 Cookie キャッシュ運用 cookieCache 有効? session: { cookieCache: { Yes → 署名/暗号化して Cookie にキャッシュ = ほぼ stateless / No → 毎回保存先を参照 maxAge: 5 * 60, refreshCache: false }, } 完全ステートレスは即時 revoke が効きにくいトレードオフ。
03 — コア機構 Rate limit — customRules と storage rateLimit:
{ -/ 本番モードでは既定で有効 enabled: true, -/ 秒 window: 60, -/ window 内の最大リクエスト数 max: 100, storage: "secondary-storage", storage の3択 memory(既定)/ database / secondary-storage。サーバーレ ス‧複数インスタンスでは memory はカウンタが分裂する。 customRules: { "/sign-in/email": { window: 10, max: 3 }, customRules "/two-factor-*": async パス単位で { window, max } を上書き。関数で動的算出も可。 }),}, } (request) -> ({ window: 10, max: 3 プラグインも独⾃ルールを持つ 例: twoFactor は /two-factor/* に専⽤のレート制限。
APPENDIX 04 Authentication 認証⽅式 Email & Password / OAuth‧ソーシャルログイン /
Generic OAuth
04 — 認証方式 Email & Password — enabled: true だけ
DB アダプタさえあれば追加要件なし。signUp / signIn のエンドポイントが即有効になる。 auth.ts auth-client.ts import { betterAuth } from "better-auth"; export import { createAuthClient } from "better-auth/client" ; const auth = betterAuth({ emailAndPassword: { enabled: true , }, }); export const sc-camel-auth-client = createAuthClient({ baseURL: "http:-/localhost:3000" , });
04 — 認証方式 サインアップ / サインインのコード例 -/ name / email
/ password は必須 const { data, error } = await authClient.signIn.email({ email: const { data, error } = await "
[email protected]
", password: "password1234", authClient.signUp.email({ name: "John Doe", email: -/ 既定 true rememberMe: true, "
[email protected]
", password: "password1234", callbackURL: "/dashboard" , }); -/ 任意 image: "https:-/example.com/image.png", -/ 任意 callbackURL: "https:-/example.com/callback" , }); rememberMe: false でブラウザを閉じた時点でセッション失効。戻り値 は { data, error }(Result 型的)。
04 — 認証方式 emailAndPassword — 主な設定オプション オプション 既定値 説明 enabled
false Email & Password 認証を有効化 disableSignUp false サインアップのみ無効化(招待制で利⽤) minPasswordLength 8 パスワードの最⼩⽂字数 requireEmailVerification false メール未検証ユーザーのサインインをブロック revokeSessionsOnPasswordReset false パスワードリセット時に全セッション失効 他: maxPasswordLength / autoSignIn / sendResetPassword / onPasswordReset / resetPasswordTokenExpiresIn / password(hash 差し替え)→ docs 参照
04 — 認証方式 メール検証 emailVerification: { sendVerificationEmail: async ({ user,
url, token }) -> { void sendEmail({ to: user.email, subject: "メールアドレスを確認し てください", text: `確認リンク: ${url}` ,});}, -/ サインアップ時に自動送信 sendOnSignUp: true , }, emailAndPassword: { enabled: true, -/ 未検証は不可 requireEmailVerification: true , }, -/ 検証メールを再送 await authClient.sendVerificationEmail({ email: "
[email protected]
", callbackURL: "/" , }); -/ トークンで明示的に検証 await authClient.verifyEmail({ query: { token: "--." }, });
04 — 認証方式 列挙攻撃(user enumeration)対策 未登録メールで サインアップ 登録済みメールで サインアップ →
→ 200 200 OWASP 認証ベストプラクティス準拠 requireEmailVerification 有効時、または autoSignIn: false の とき発動。攻撃者が登録済みアドレスを推測できない。 既存ユーザーの再サインアップを検知したい場合は onExistingUserSignUp コールバック。 どちらでも同⼀の 200 を返す
04 — 認証方式 パスワードリセット — 3ステップ 1 サーバー: 送信処理を実装 emailAndPassword:
{ enabled: true, revokeSessionsOnPasswordReset: true, sendResetPassword: async ({ user, url, token }) -> { void sendEmail({ to: user.email, text: `再設定: ${url}` }); }, onPasswordReset: async ({ user }) -> { -/ 監査ログ・通知 }, } 2 クライアント: リセット要求 const { data, error } = await authClient.requestPasswordReset({ email: "
[email protected]
", redirectTo: "https:-/example.com/reset-passwor d" , }); -/ 旧 forgetPassword は非推奨 3 リンク先: 新パスワード設定 const { data: reset, error : resetError } = await authClient.resetPassword({ newPassword: "password1234", -/ URL クエリから取得 token, });
04 — 認証方式 パスワードポリシー emailAndPassword: { enabled: true, -/ 既定
8 ⻑さは minPasswordLength / maxPasswordLength で設定。 minPasswordLength: 12, -/ 既定 128 maxPasswordLength: 256 , } ⽂字種の必須化(記号‧数字など)はコアに含まれない — Valibot 等の境界バリデーションか before フックで実装する。
04 — 認証方式 ハッシュ⽅式のカスタム — scrypt → Argon2id 既定は scrypt(メモリハード、Node.js
ネイティブ実装あり)。hash / verify の差し替えで任意アルゴリズムに。 -/ password.ts — @node-rs/argon2 const opts: Options = { -/ 64 MiB memoryCost: 65536, timeCost: 3, parallelism: 4, outputLen: 32, -/ Argon2id algorithm: 2 , }; export async function hashPassword(password) { return await hash(password, opts); } export async function verifyPassword({ password, hash }) { return await verify(hash, password, opts); } emailAndPassword: { enabled: true, password: { hash: hashPassword, verify : verifyPassword, }, } verify は { password, hash } → boolean。引数の形が hash 関数 と異なる点に注意。
04 — 認証方式 OAuth 設定例 — Google / LINE socialProviders:
{ google: { clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, -/ 任意 prompt: "select_account" , }, line: { clientId: process.env.LINE_CLIENT_ID, clientSecret: process.env.LINE_CLIENT_SECRET, -/ scope: ["custom"], -/ disableDefaultScope: true, }, } LINE Developers Console — 事前設定4ステップ 1 チャネルを作成 2 Channel ID / Channel secret を控える 3 Redirect URI を登録 — ローカルは http:-/localhost:3000/api/auth/callback/line 4 スコープ有効化 — 最低 openid、名前‧アバター‧メールは profile / email を追加
04 — 認証方式 signIn.social と ID トークンサインイン await authClient.signIn.social({ -/
"google" など provider: "line", callbackURL: "/dashboard", errorCallbackURL: "/error", -/ 新規のみ newUserCallbackURL: "/welcome" , }); 複数クライアント ID の受理 Web iOS Android → 単⼀バックエンド Google / Apple / Microsoft Entra / Facebook / Cognito は clientId に配列 を渡すと複数クライアント ID を受理 — ネイティブ SDK の トークンをクロスプラットフォームで検証できる。
04 — 認証方式 対応プロバイダ⼀覧 — 地域選好まで組み込み 主要 ID 基盤 Google
/ Apple / Microsoft / Facebook ⽇本‧アジア‧ロシア向け LINE / Kakao(Kakao Talkの運営元) / Naver(韓国最⼤の検索エンジン) / VK(ロシアのSNSアプリ) 開発者 / コード GitHub / GitLab / Hugging Face(AI‧機械学習版のGitHub) チャット / コミュニティ Discord / Slack / Twitch / Reddit / Kick(ライビ配信プラットフォーム) ⽣産性 / SaaS Notion / Atlassian / Linear / Figma / Dropbox / Salesforce / Vercel / Zoom / LinkedIn メディア / ソーシャル Twitter/X / TikTok / Spotify / Roblox クラウド ID Amazon Cognito
04 — 認証方式 Generic OAuth — OAuth 2.0 / OIDC
なら何でも接続 社内 IdP、Auth0 / Keycloak / Okta、Instagram / Coinbase 等の独⾃ OAuth もこれで扱う。 import { genericOAuth } from "better-auth/plugins"; plugins : [ genericOAuth({ config: [{ providerId: "custom-oauth", clientId: process.env.CUSTOM_CLIENT_ID, clientSecret: process.env.CUSTOM_CLIENT_SECRET, authorizationUrl: "https:-/auth.example.com/authorize", tokenUrl: "https:-/auth.example.com/token", issuer: "https:-/auth.example.com", scopes: ["openid", "profile", "email" ], }], }), ] -/ クライアント側の対プラグイン plugins: [genericOAuthClient()] -/ サインインは providerId を渡す await authClient.signIn.oauth2({ providerId: "custom-oauth", callbackURL: "/dashboard" , }); 組み込み⽤の provider とは別 — Generic OAuth は providerId を渡す signIn.oauth2。
04 — 認証方式 プリセットヘルパー — URL ⼿書き不要 import { genericOAuth,
slack } from "better-auth/plugins"; plugins : [ genericOAuth({ auth0 keycloak microsoftEntraId config : [ okta slack slack({ clientId: process.env.SLACK_CLIENT_ID, hubspot clientSecret : process.env.SLACK_CLIENT_SECRET, line patreon ], }), ] }),
04 — 認証方式 ⼿動設定 と OIDC discoveryUrl ⾃動設定 Instagram(⼿動) {
providerId: "instagram", clientId: --., clientSecret: --., authorizationUrl: "https:-/api.instagram.com/oauth/au thorize" , tokenUrl: "https:-/api.instagram.com/oauth/ac cess_token" , scopes: ["user_profile","user_media" ], } Coinbase(⼿動) { providerId: "coinbase", clientId: --., clientSecret: --., authorizationUrl: "https:-/www.coinbase.com/oauth/aut horize" , tokenUrl: "https:-/api.coinbase.com/oauth/tok en" , scopes: ["wallet:user:read" ], } OIDC は discoveryUrl だけ { providerId: "my-provider", discoveryUrl: "https:-/auth.example.com/.well-kno wn/openid-configuration" , clientId: "--.", clientSecret: "--." , } -/ authorizationUrl / tokenUrl / -/ userInfoUrl / issuer を自動取得
04 — 認証方式 GenericOAuthConfig — 設定オプション フィールド 説明 providerId プロバイダ識別⼦(必須)。signIn.oauth2
の providerId と⼀致させる clientId / clientSecret OAuth クライアント ID / シークレット(必須) discoveryUrl OIDC/OAuth 設定の⾃動取得 URL。各エンドポイントを補完 scopes 要求するスコープ pkce PKCE を有効化するか 他: issuer / requireIssuerValidation / authorizationUrl / tokenUrl / userInfoUrl / redirectURI / responseType / prompt / accessType / accessTokenExpiresIn / getUserInfo → docs 参照 ※ magic link / Email OTP / username / phone / anonymous は認証系プラグイン → 第6章で扱う。
APPENDIX 05 Integrations フレームワーク統合 思想 / 対応⼀覧 / Next.js‧Hono‧Expo の代表3例
05 — フレームワーク統合 思想 — route handler を差し込むだけ Request →
auth.handler コアの正体はWeb Fetch 標準の単⼀関数 。統合 = catch-all ルート 1本に auth.handler を渡すだけ。Request → Response を扱える⼟ 台なら Deno / Bun / Cloudflare Workers でも動く。 → Promise<Response> 公式ヘルパ(toNextJsHandler / toNodeHandler)は型の橋渡 しをする糖⾐にすぎない — 無くても直接呼べる。
05 — フレームワーク統合 対応⼀覧① フロント / フルスタック — すべて公式 フレームワーク
差し込み⼝(catch-all) ハンドラ Next.js app/api/auth/[--.all]/route.ts toNextJsHandler(auth) Nuxt server/api/auth/[--.all].ts auth.handler(toWebRequest(event)) SvelteKit src/hooks.server.ts svelteKitHandler({--.}) SolidStart routes/api/auth-*all.ts toSolidStartHandler(auth) Astro pages/api/auth/[--.all].ts auth.handler(ctx.request) React Router v7 / Remix app/routes/api.auth.$.ts(resource route) loader / action で auth.handler TanStack Start src/routes/api/auth/$.ts auth.handler(request)
05 — フレームワーク統合 対応⼀覧② バックエンド フレームワーク 区分 差し込み⼝ / ハンドラ
Hono 公式 app.on(["POST","GET"], "/api/auth-*") → auth.handler(c.req.raw) Fastify 公式 /api/auth-* catch-all → Node req を Request 変換後 auth.handler Express 公式 app.all("/api/auth-*splat") → toNodeHandler(auth) Elysia 公式 /api/auth-* を mount → auth.handler Nitro 公式 server/routes/api/auth/[--.all].ts → auth.handler(toWebRequest(event)) Convex 公式 @convex-dev/better-auth(公式コンポーネント) NestJS コミュニティ @thallesp/nestjs-better-auth — AuthModule + catch-all Encore コミュニティ raw endpoint の catch-all → auth.handler(request)
05 — フレームワーク統合 対応⼀覧③ モバイル / デスクトップ プラットフォーム 区分 クライアント側
Expo 公式 @better-auth/expo expoClient({ scheme, storage }) Lynx 公式(ByteDance) createAuthClient Electron コミュニティ renderer から createAuthClient モバイルアプリ → 既存の auth.handler サーバを新設しない — 既存サーバをそのまま叩く。プラット フォーム差分は「Cookie の保存先」と「ディープリンクの scheme」に集約される。
05 — フレームワーク統合 代表コード例1 — Next.js app/api/auth/[...all]/route.ts サーバコンポーネント / Server
Action import { auth } from "@/lib/auth"; import { auth } from "@/lib/auth"; import { toNextJsHandler } from import { headers } from "next/headers"; "better-auth/next-js"; const session = await auth.api.getSession({ headers: export const { POST, GET } = toNextJsHandler(auth); await headers(), });
05 — フレームワーク統合 代表コード例2 — Hono import { Hono }
from "hono"; import { serve } from "@hono/node-server"; import { auth } from "./auth"; const app = new Hono(); catch-all ルートを1本切り、Web 標準の c.req.raw を 渡すだけ。 app.on(["POST", "GET"], "/api/auth-*", (c) -> { return auth.handler(c.req.raw); }); serve(app); 別オリジンから叩くなら cors ミドルウェアは認証ルート より前 に登録する(プリフライトを先に処理させる)。
05 — フレームワーク統合 代表コード例3 — Expo(2ステップ) 1 サーバー — expo()
+ trustedOrigins import { expo } from "@better-auth/expo"; export const auth = betterAuth({ plugins: [expo()], trustedOrigins: ["myapp:-/" ], }); 2 クライアント — Cookie を SecureStore に保存 import { expoClient } from "@better-auth/expo/client" ; import * as SecureStore from "expo-secure-store"; export const sc-camel-auth-client = createAuthClient({ baseURL: "http:-/localhost:8081", plugins : [ expoClient({ scheme: "myapp", storagePrefix: "myapp", storage : SecureStore, }), ], });
05 — フレームワーク統合 まとめ — 3例に共通する同⼀構造 Next.js Hono Expo toNextJsHandler(auth)
auth.handler(c.req.raw) 既存の auth.handler を流用 常に「Request →auth.handler→ Response」。 新フレームワークが出ても、Web 標準を扱える限り統合は数⾏で済む。
APPENDIX 06 Plugins プラグイン⼤全 認証系 / 認可‧承認系 / 企業系 /
ユーティリティ / 決済
06 — プラグイン大全 共通の注意 — 全プラグイン導⼊の3ステップ 1 サーバー plugins: [...]
に追加 → 2 クライアントに対応プラグイン追加 → 3 スキーマ再⽣成‧マイグレーション 専⽤パス import: サーバー better-auth/plugins / クライアント better-auth/client/plugins 。個別サブパスは存在しない(例外は better-auth/plugins/access のみ)。 独⽴パッケージ組: Passkey @better-auth/passkey / Stripe @better-auth/stripe / SSO @better-auth/sso / Polar @polar-sh/better-auth / Dub @dub/better-auth npx @better-auth/cli generate npx @better-auth/cli migrate 追加‧変更のたびに再実⾏必須 — 忘れるとスキーマ不整合で実⾏時に 落ちる。
06 — プラグイン大全 / 認証系 認証系プラグイン 早⾒表(10種) プラグイン 役割 主な設定‧API
Two-Factor (2FA) TOTP‧OTP‧バックアップコード‧信頼済みデバイス twoFactor() / twoFactorClient() Username メールに加えユーザー名でログイン username({ minUsernameLength }) Anonymous PII なしで認証済み体験 → 後から本アカウントへリンク(ゲスト→ 本登録) anonymous({ onLinkAccount }) Phone Number 電話番号 + SMS OTP(SMS 送信は⾃前) phoneNumber({ sendOTP }) Magic Link メールリンクでパスワードレス(送信は⾃前) magicLink({ sendMagicLink }) Email OTP メール OTP でサインイン/検証/リセット emailOTP({ sendVerificationOTP }) Passkey WebAuthn/FIDO2 パスワードレス passkey({ rpID, rpName, origin }) Generic OAuth 任意の OAuth2 / OIDC を追加(→ 第4章) genericOAuth({ config }) One Tap Google One Tap のワンタップログイン oneTap() / oneTapClient({ clientId }) SIWE Sign-In with Ethereum(ERC-4361) siwe({ domain, getNonce }) 薄い背景の5種 = 軽量‧補助枠(Username / Anonymous / Phone Number / Magic Link / One Tap)
06 — プラグイン大全 / 認証系 Two-Factor(2FA) TOTP‧メール/SMS OTP‧バックアップコード‧信頼済みデバイスを⼀括提供。ログイン後に第⼆要素検証フローを挿⼊する。 サインイン →
チャレンジ(第⼆要素) → 検証 → セッション import { twoFactor } from "better-auth/plugins"; import { twoFactorClient } from "better-auth/client/plugins"; plugins : [ twoFactor({ -/ 認証アプリ上の表示名 twoFactorClient({ onTwoFactorRedirect() { issuer: "MyApp", -/ 検証ページへプログラム的に遷移 otpOptions: { async sendOTP({ user, otp }) { },}), -/ メール/SMS で otp を送信(自前) }, }), ] plugins : [ ]
06 — プラグイン大全 / 認証系 Email OTP — 1機構で3⽤途 import
{ emailOTP } from "better-auth/plugins"; plugins : [ emailOTP({ otpLength: 6, -/ 秒 expiresIn: 300, async sendVerificationOTP({ email, otp, type }) { -/ email 宛に otp を送信 }, emailOTP() ↓ type で分岐 "sign-in" サインイン }), ] "email-verification" メール検証 "forget-password" パスワードリセット await authClient.emailOtp.sendVerificationOtp({ email: "
[email protected]
", type: "sign-in" , });
06 — プラグイン大全 / 認証系 Passkey — WebAuthn / FIDO2
⽣体‧PIN‧セキュリティキーによるパスワードレス。フィッシング耐性。独⽴パッケージ @better-auth/passkey。 import { passkey } from "@better-auth/passkey"; plugins : [ passkey({ -/ ローカルは localhost rpID: "example.com", rpName: "My App", origin: "https:-/example.com" , }), ] -/ クライアントでパスキー登録 await authClient.passkey.addPasskey({ name: "Primary passkey" , }); 登録レーン addPasskey → デバイスの⽣体/PIN で鍵ペア⽣成 → 公開鍵 をサーバー保存 認証レーン チャレンジ署名をデバイス内の秘密鍵で実施 — パスワードが 存在しないためフィッシング不可
06 — プラグイン大全 / 認証系 SIWE — Sign-In with Ethereum(ERC-4361)
ウォレット署名で認証。nonce ⽣成‧署名検証は⾃前実装(viem 推奨)— verifyMessage は署名復元のみ、nonce / ドメイン / Chain ID / 期限の 検証はプラグイン側。 import { siwe } from "better-auth/plugins"; plugins : [ siwe({ domain: "myapp.com", -/ メール紐付けユーザーを作成 anonymous: false, getNonce: async () -> generateSecureNonce(), verifyMessage: async ({ message, signature, address }) -> { return await verifySignature({ message, signature, address }); }, }), ] ウォレットが署名 ↓ 署名検証 + nonce/期限チェック ↓ セッション発⾏
06 — プラグイン大全 / 認可・承認系 認可‧承認系 早⾒表(5種) プラグイン 役割 主な設定‧API
Admin ユーザー管理‧ロール付与‧BAN‧なりすまし admin({ adminRoles }) Agent Auth AI エージェント固有 identity‧登録‧discovery‧capability 認可(策定 中標準の実装、API 流動的 — 本番採⽤は慎重に) → 第9章で詳説 API Key API キーの発⾏‧管理‧検証。レート制限‧有効期限‧メタデータ apiKey() / verifyApiKey() MCP ⾃アプリを MCP クライアント向け OAuth プロバイダ化 mcp({ loginPage }) Organization 組織‧メンバー‧招待‧チーム‧RBAC のマルチテナント中核 organization({ ac, teams })
06 — プラグイン大全 / 認可・承認系 Admin — 管理ダッシュボードの⼟台 import {
admin } from "better-auth/plugins"; plugins : [ admin({ adminRoles: ["admin", "superadmin"], adminUserIds: ["user_id_1"], impersonate(なりすまし) -/ 既定1時間 対象ユーザーのセッションを再現してデバッグ‧サポート対応。 なりすましセッションは既定1時間。 impersonationSessionDuration: 60 * 60, defaultBanReason: "規約違反" , }), BAN / 解除 ] banReason 付きで停⽌‧復帰を管理。 -/ クライアント 管理者の指定 await authClient.admin.impersonateUser({ userId: "user-id" adminRoles か adminUserIds で。 }); await authClient.admin.banUser({ userId: "user-id", banReason: "spam" });
06 — プラグイン大全 / 認可・承認系 API Key — プログラムアクセスの認証 import
{ apiKey } from "better-auth/plugins"; plugins : [ apiKey({ キー付きリクエスト rateLimit: { enabled: true, ↓ verifyApiKey maxRequests: 100 }, enableMetadata: true , }), ] -/ キー検証(権限チェック付き) const { valid } = await auth.api.verifyApiKey({ body: { key: "the_api_key", permissions: { files: ["read" ] } }, }); 許可 拒否 ビルトインのレート制限‧カスタム有効期限‧残回数制限‧メタ データ‧パーミッションに対応。
06 — プラグイン大全 / 認可・承認系 MCP — ⾃アプリを OAuth プロバイダ化
MCP クライアント向けにアクセストークンを発⾏‧管理。withMcpAuth で MCP サーバを保護。別プロセス/別⾔語には Bearer リモート検証の 軽量 MCP Client。 import { mcp } from "better-auth/plugins"; plugins : [ mcp({ loginPage: "/sign-in", -/ 未認証クライアントの誘導先 MCP クライアント → ⾃アプリ → トークン発⾏‧保護 }), ] 近く OAuth Provider プラグインへ統合予定 (スキーマは OIDC Provider と共通)— 新規実装は移⾏先を意識する。
06 — プラグイン大全 / 認可・承認系 Organization — マルチテナントの中核 import {
organization } from "better-auth/plugins"; import { ac } from "@/auth/permissions"; plugins : [ organization({ -/ 動的アクセス制御に必須 ac, teams: { enabled: true }, dynamicAccessControl: { enabled: true, maximumRolesPerOrganization: 10 , }, }), ] -/ クライアント側もペアで plugins: [organizationClient({ teams: { enabled: true } })] 組織(Organization) ↓ メンバー チーム 招待 RBAC ロール ac + dynamicAccessControl で実⾏時に組織ごとのカスタムロールを ⽣成できる。
06 — プラグイン大全 / 企業系 企業系 早⾒表 + OAuth Provider
への合流 プラグイン 役割 OIDC Provider ⾃前の OpenID Connect プロバイダを構築(OAuth Provider へ移⾏予定) OAuth Provider OIDC Provider と MCP を束ねる後継統合プラグイン SSO 外部の SAML 2.0 / OIDC / OAuth2 を「消費」して SSO ロ グイン SCIM SCIM サーバを公開しディレクトリ同期‧⾃動プロビ ジョニング OIDC Provider MCP ↓ 合流 OAuth Provider(単⼀窓⼝へ)
06 — プラグイン大全 / 企業系 OIDC Provider — ⾃社をログイン基盤に import
{ oidcProvider } from "better-auth/plugins"; plugins : [ oidcProvider({ loginPage: "/sign-in", サードパーティアプリ → ⾃社 = OIDC プロバイダ consentPage: "/oauth/consent", getAdditionalUserInfoClaim: async (user, scopes, client) -> { return { role : user.role }; }, }), ] 認可コードフローでログインを提供。loginPage / consentPage は 差し替え可能、getAdditionalUserInfoClaim で UserInfo に独⾃ク レームを追加。
06 — プラグイン大全 / 企業系 SSO — 企業 IdP を「消費」する
import { sso } from "@better-auth/sso"; plugins : [ sso({ organizationProvisioning: { disabled: false, defaultRole: "member" , }, }), ] 企業 IdP(Okta / Entra ID …) ↓ SAML 2.0 / OIDC / OAuth2 await auth.api.registerSSOProvider({ body: { providerId: "acme-corp", issuer: "https:-/acme.okta.com", domain: "acmecorp.com", organizationId: "org_acme_id", samlConfig: { -* メタデータ・証明書 -/ headers, }); SSO プラグイン(@better-auth/sso) ↓ 組織⾃動プロビジョニング‧ロール付与 } },
06 — プラグイン大全 / 企業系 SCIM — ディレクトリ同期を受け付ける 外部 IdP(Okta
/ Entra ID) → scim() ユーザー / グループの⾃動プロビジョニングを受け付 ける SCIM サーバを公開。属性は既定でコアフィール ドへ⾃動マッピング(カスタマイズ可)。 → 作成‧更新‧無効化を⾃動同期 scim() / auth.api.getSCIMResourceType() 。エン タープライズのディレクトリ同期要件で使う。
06 — プラグイン大全 / ユーティリティ ユーティリティ系 早⾒表(9種) プラグイン 役割 備考
Bearer Token Cookie の代わりに Bearer トークンで API 認証 利⽤は慎重に(Cookie 推奨) Device Authorization OAuth 2.0 デバイス認可グラント(RFC 8628) CLI‧TV‧IoT 向け Have I Been Pwned 漏洩済みパスワードの利⽤を拒否 k-匿名性チェック i18n 認証エラーメッセージ等の多⾔語化 ⽂⾔ローカライズ Last Login Method 最後に使った認証⼿段を記録‧表⽰ 「前回は Google」表⽰ Multi-Session 同⼀ブラウザで複数アカウントの同時セッション(maximumSessions) アカウント切替 UX OAuth Proxy OAuth リクエストをプロキシ — redirect URL が確定しないプレビュー環境向け 開発時の救済 One-Time Token 単回使⽤トークンの⽣成‧検証 クロスドメイン受け渡し Test utilities 認証フローのテスト⽤ヘルパー E2E / 結合テストの⾜場
06 — プラグイン大全 / ユーティリティ Captcha — サインアップ / イン
/ リセットのボット対策 import { captcha } from "better-auth/plugins"; plugins : [ captcha({ -/ google-recaptcha | hcaptcha | captchafox provider: "cloudflare-turnstile", secretKey : process.env.TURNSTILE_SECRET_KEY!, }), ] フォーム送信 → チャレンジ検証 → 通過 / ブロック 対応: Cloudflare Turnstile / Google reCAPTCHA / hCaptcha / CaptchaFox。 endpoints で保護対象を上書き。reCAPTCHA v3 は minScore、hCaptcha / CaptchaFox は siteKey を追加指定。
06 — プラグイン大全 / ユーティリティ JWT — 外部サービス連携⽤のトークン発⾏ import {
jwt } from "better-auth/plugins"; plugins : [ jwt({ jwks: { -/ ES256 / RSA256 / PS256 も可 keyPairConfig: { alg: "EdDSA" }, }, }), ] JWT 取得エンドポイント → 外部サービスが JWKS で検証 セッションの置き換えではない — JWT を要求する外部サービス連携向 け。検証⽤ JWKS エンドポイントも提供する。
06 — プラグイン大全 / ユーティリティ OpenAPI — 全エンドポイントをリファレンス化 import {
openAPI } from "better-auth/plugins"; plugins : [ openAPI({ -/ UI の公開パス path: "/reference" , ] }), /reference — Scalar UI POST /sign-up/email POST /two-factor/verify-totp GET /organization/list コア + 全プラグインを OpenAPI 3.1.1 で出⼒。Scalar 製 UI でブラウズ‧実⾏テス ト。開発初期の動作確認 UI としても有⽤。
06 — プラグイン大全 / その他 Dub — リンク経由サインアップのリードトラッキング import {
dubAnalytics } from "@dub/better-auth"; import { Dub } from "dub"; plugins : [dubAnalytics({ dubClient: new Dub(),}),] Dub リンク経由のサインアップを計測し、リードを追跡する。 決済ではなくグロース / アナリティクス⽤途。OAuth リンキングのサポー トも追加する。
06 — プラグイン大全 / その他 ⾃作プラグイン / コミュニティプラグイン -/ plugin.ts
import type { BetterAuthPlugin } from "better-auth"; import { createAuthEndpoint, sessionMiddleware } from "better-auth/api"; export const sc-camel-my-plugin = () -> ({ id: "my-plugin", endpoints: { hello: createAuthEndpoint( "/my-plugin/hello" ,{ method: "POST", body: z.object({ name: z.string() }), use: [sessionMiddleware] }, async (ctx) -> ctx.json({ message: `hi ${ctx.body.name}` }), ), }, }) satisfies BetterAuthPlugin; ⾃作 satisfies BetterAuthPlugin なオブジェクトを返す関数。 createAuthEndpoint + sessionMiddleware / requireResourceOwnership。独⾃テーブルは schema 宣⾔ → CLI 再⽣成。 コミュニティ ⽤途特化の拡張が多数。公式⼀覧から探せる‧⾃作の登録も 可。
06 — プラグイン大全 / 決済 決済プラグイン群 (1/2) — 位置づけと3モデル Stripe
/ Polar は公式保守、Autumn / Dodo / Creem / Chargebee / Commet はベンダー保守(いずれも公式 docs にプラグインページあり)。 朱⾊ = MoR(税 /VAT を丸投げできるモデル)— 決済プラグイン選定の最⼤の分岐点。 ① 直接 PSP ② MoR(Merchant of Record) ③ 上乗せ層 Stripe Polar / Dodo / Creem / Commet Autumn / Chargebee createCustomerOnSignUp‧subscription (plans / freeTrial / limits / upgrade 差額課 ⾦)‧Webhook ⾃動処理。 販売者を肩代わり。Polar は開発者ファース ト MoR — GitHub 連携‧ベネフィット⾃動 付与、checkout / portal / usage / webhooks。 Autumn = Stripe 上の宣⾔的課⾦レイヤー (attach / check / track)。Chargebee = サ ブスク / レベニュー管理層。 税の最終責任 = ⾃社 stripe() / polar() / autumn() 税/VAT の登録‧計算‧申告‧納税を代 ⾏ 税の最終責任 = ⾃社
06 — プラグイン大全 / 決済 決済プラグイン群 (2/2) — 残る4種と選び⽅ Dodo
Creem Chargebee Commet 150+カ国グローバル MoR。クレ ジット課⾦‧使⽤量メータリング 内蔵 税コンプラ込み MoR + レベ ニュースプリット内蔵 PSP の上のサブスク管理層 — プ ロレーション‧多通貨 ‧RevRec‧ダニング‧複数 PSP AI/API 課⾦⼀気通貫 MoR — portal / subscriptions / features / usage / seats 要件‧状況 推奨 税/VAT を丸投げ(MoR)したい Polar / Dodo / Creem / Commet 直接 PSP で最⼤の柔軟性 Stripe Stripe は残して AI/SaaS の従量‧クレジット Autumn グローバル販売(150+カ国)を最速で Dodo Payments 収益分配(レベニュースプリット)込み Creem エンタープライズの複雑サブスク‧収益認識 Chargebee AI 従量 + feature gating + seat を MoR で Commet dodopayments() / creem() / chargebee() / commet()
APPENDIX 07 Infrastructure Infrastructure 公式の有料運⽤レイヤー — Dashboard / Security /
Email / Enterprise
07 — Infrastructure 位置づけ — ライブラリが埋めない「運⽤」を肩代わり Dashboard Security ① ユーザー‧組織‧セッションを眺めて操作する管理画⾯
② クレデンシャルスタッフィングやボットの不正検知‧遮断 Email & SMS Enterprise ③ 検証‧リセット‧招待メールの確実な配信 コア(無料‧OSS‧⾃前ホスト) 外周 = Infrastructure(有料マネージド‧4本柱) ④ エンタープライズ向け SSO / SCIM / ログドレイン dash() / sentinel() の実体もプラグイン — 違いは接続先が有料マネージド である点だけ。
07 — Infrastructure 導⼊はプラグイン1⾏ 1 install → 2 env(API_KEY のみ必須)
→ 3 サーバー → 4 クライアント # npm install @better-auth/infra import { dashClient, sentinelClient } from # BETTER_AUTH_API_KEY=--. のみ必須 "@better-auth/infra/client"; import { dash, sentinel } from "@better-auth/infra"; plugins : [ plugins : [ dashClient(), dash({ apiKey : process.env.BETTER_AUTH_API_KEY }), sentinelClient({ autoSolveChallenge: true }), sentinel({ apiKey : process.env.BETTER_AUTH_API_KEY }), -/ sentinel は Pro 以上 -/ フィンガープリント + PoW 自動解決 ] ] Expo / RN は @better-auth/infra/native 。dash と sentinel は独⽴ 利⽤可、両⽅で全機能。
07 — Infrastructure アーキテクチャ — 観測‧判定‧配信だけを委譲する ⾃分のアプリ(⾃前ホスト) DB とユーザーデータは⾃前に残る クライアントは
X-Visitor-Id を付与、PoW は X-PoW-Solution で再送 イベント送信(dash) → リクエスト検査(sentinel) ⇄ 管理 GUI(/dash/*) ← 監査ログ(/events/*) ⇄ Infra 障害でも認証フロー本体は⽌めない設計。判定は log / challenge / block。 Better Auth Infra(マネージド) 分析‧検知‧配信の「運⽤知能」のみ タイムアウト既定: API 3000ms / KV 1000ms
07 — Infrastructure / 4本柱① 柱①: Dashboard dash() dash({ apiKey:
process.env.BETTER_AUTH_API_KEY, -/ 既定 apiTimeout: 3000, kvTimeout: 1000, activityTracking: { enabled: true, -/ 既定5分 updateInterval: 300000 , }, }) -/ lastActiveAt 列が追加される -/ → 有効化後マイグレー ション必須 ベストプラクティス: API キー必須 / トラッキング間隔は慎重に / ログ 保持はプラン依存 / エンドポイントは権限を適切に。 ⼊れるだけで有効になるもの イベント⾃動収集 ⼿動計装不要。全認証イベントを記録 管理 API 群 /dash/users‧/dash/user/ban‧/dash/user/impersonat e‧/dash/sessions‧/dash/session/revoke‧組織 / チー ム / 招待‧エンタープライズ‧2FA 分析 /dash/stats‧/dash/graph‧/dash/retention‧/dash/m ap 監査ログ照会 /events/list‧/events/audit-logs‧/events/types
07 — Infrastructure / 4本柱② 柱②: Security sentinel() — 包括的不正対策(Pro
以上) リクエスト → 判定 → log(記録のみ) challenge(PoW‧難易度既定18) クレデンシャルスタッフィン グ 失敗しきい値→challenge→block (windowSeconds / cooldownSeconds) 不可能移動 maxSpeedKmh 超の地理移動を検知 トライアル悪⽤ フィンガープリント(maxAccountsPerVisitor) 漏洩パスワード HIBP k-匿名性 — フルパスワード⾮送信 休眠アカウント再活性化 staleDays(乗っ取り兆候の通知) その他 ジオブロック(allow/denyList)‧ボット‧不審 IP‧ベロシティ‧使い捨てメール遮断 (strictness: low/medium/high)‧メール正規化 (プラスタグ除去) block(遮断) sentinel({ security: { credentialStuffing: { enabled: true, thresholds: { challenge: 3, block: 5 }, windowSeconds: 3600, cooldownSeconds: 900 , }, impossibleTravel: { enabled: true, maxSpeedKmh: 1000, action: "challenge" , }, compromisedPassword: { enabled: true, action: "block" , }, challengeDifficulty: 18 , }, }) ベストプラクティス: まず log から → しきい値調整 → block より先に challenge。イベントは security_* として監査ログへ。
07 — Infrastructure / 4本柱③ 柱③: Email Service — マネージド配信(Pro
以上) import { sendEmail } from "@better-auth/infra"; -/ 認証フローのコールバックから呼ぶだけ async sendResetPassword({ user, url }) { await sendEmail({ template: "reset-password", to: user.email, variables: { resetLink: url, userEmail: user.email, appName: "Your App" }, }); } -/ 戻り値 { success, messageId?, error? } 本番は送信を await しない (タイミング攻撃回避)。サーバーレスは waitUntil。 組み込みテンプレート13種 verify-email / reset-password / change-email / sign-in-otp / verify-email-otp / reset-password-otp / magic-link / two-factor / invitation / application-invite / delete-account / stale-account-user / stale-account-admin AWS SES SendGrid Resend
07 — Infrastructure / 4本柱④ 柱④: Enterprise — SSO /
SCIM / ログドレイン SSO SCIM ログドレイン /dash/organization/sso-providers /directories /directory /log-drains /log-drain /sso-provider /directory/token /log-drain/test ディレクトリ同期‧⾃動プロビジョニング SIEM 転送で⻑期保管‧相関分析 /sso-provider/verify-domain 企業 IdP との SAML / OIDC 接続を組織単位 で管理 すべて dash() のエンドポイント群に統合。ダッシュボードはロールベースアクセス前提。
07 — Infrastructure Audit Logs — 発⽣ → 捕捉 →
蓄積 → 照会 ユーザー / セッション系 組織系 セキュリティ系 user_signed_up / user_signed_in / session_created / user_impersonated / password_changed / account_linked / email_verification_sent … organization_created / member_added / member_role_updated / invite_accepted / team_created … security_blocked / security_credential_stuffing / security_impossible_travel …(sentinel 使⽤時) const logs = await authClient.dash.getAuditLogs({ session: session.data, limit: 50, offset: 0, -/ eventType / organizationId / userId / -/ identifier で絞り込み可 }); -/ イベント配列 -/ limit/offset ループで全件取得可 logs.data-.events; getAuditLogs ⾃ユーザーのイベント(organizationId で組織スコープに) getAllAuditLogs admin / owner 権限組織の全件(organization プラグイン必須) limit 最⼤100‧既定50 / offset 既定0
07 — Infrastructure 料⾦プラン構造(docs 記載ベース) Enterprise Pro + SSO /
SCIM / ログドレイン + 監査ログ⻑期 保持 + sentinel(不正対策) + Email Service 無料 dash 基本(イベント収集‧管理 API) 価格: —(要公式確認) 価格: —(要公式確認) 価格: —(要公式確認) docs には「sentinel = Pro 以上」「Email = Pro 以上」「ログ保持 = プラン依存」の⾔及のみ。価格数値は登壇直前に公式で確認。
07 — Infrastructure / ビジネスモデル ビジネスモデル (1/2) — OSS コア
+ Infrastructure = Supabase 型 「認証ライブラリはタダ。じゃあ何で⾷ってる?」— 運⽤を売る。 OSS 普及 ① OSS コア(無料)で普及 型安全‧網羅性‧低学習コストでエコシステムを育てる。普及した OSS が販売チャネルになる。 ↓ 販売チャネル化 ↓ ② Infrastructure(有料)で収益化 ⾃前運⽤すると重い領域をマネージドで売る。 運⽤知能へ課⾦ 核は「コアは⾃前、運⽤知能だけ買う」分離 — 主権を⼿放さない。
07 — Infrastructure / ビジネスモデル ビジネスモデル (2/2) — Auth0 /
Clerk との対⽐ 観点 Auth0 / Clerk(全部ホスト) Better Auth + Infrastructure 認証コア ベンダーがホスト ⾃前ホスト(OSS‧無料) ユーザーデータ ベンダー側 ⾃前 DB に所有 課⾦対象 認証そのもの(MAU 等) 運⽤知能(分析‧不正対策‧配信) 採⽤の起点 営業‧サインアップ OSS の普及 ロックイン 強い(移⾏が重い) 弱い(コアは⼿元、有料層は着脱式) ただし有料層に寄せすぎるとロックインの芽 — どこまで委ねるか設計段階で線引きする。
08 — 比較 / なぜ◯◯ではないのか なぜ Auth0 ではないのか 良い点 業界標準。エンタープライズでの実績は随⼀、Universal
Login と機能網羅も◎。 でも データはベンダー側。MAU 従量(超過 $0.07/MAU)でスケール時に⾼額化。「全部ホスト」前提でカスタマイズはベンダー の枠内。 → Better Auth なら: データは⾃分の DB、コストは⾃分のインフラ次第。公式移⾏ガイドあり。
08 — 比較 / なぜ◯◯ではないのか なぜ Clerk ではないのか 良い点 プリビルト
UI で導⼊最速。B2C の定番、React DX は業界随⼀。 でも セッションストア‧ユーザーレコード‧署名鍵を⾃分で所有できない。データ主権とスケール時のコストは構造的な課題。 → Better Auth なら: セッションも鍵もレコードも⼿元。UI は⾃作(ヘッドレス)と引き換えに主権を取る。
08 — 比較 / なぜ◯◯ではないのか なぜ WorkOS ではないのか 良い点 エンタープライズ
SSO / SCIM の王者。auth.md などエージェント認証にも積極的(→ 第9章)。 でも B2B 特化でスタック委譲が前提。コンシューマ認証や⾃由なデータモデルは主戦場ではない。 → Better Auth なら: SSO / SCIM プラグイン + Infra Enterprise で同領域へ、コアは⾃前のまま。
08 — 比較 / なぜ◯◯ではないのか なぜ Kinde ではないのか 良い点 認証
+ 課⾦ + フィーチャーフラグの統合。無料枠(10.5K MAU)も優しい。 でも ロックイン構造は Clerk と同型 — データもフラグも課⾦状態もベンダー側。 → Better Auth なら: 課⾦統合も決済プラグイン(Stripe / Polar / Autumn…)で対抗できる(→ 6-22 / 6-23)。
08 — 比較 / なぜ◯◯ではないのか なぜ Supabase Auth ではないのか 良い点
Supabase を使っているなら⾃然な選択。セルフホストも可能。 でも BaaS 前提(GoTrue)。Postgres / RLS と密結合で、認証だけを切り出して持ち運べない。 → Better Auth なら: Supabase を「ただの Postgres」として使いながら、認証ロジックは⾃分のコードに置ける。
08 — 比較 / なぜ◯◯ではないのか なぜ OpenAuth ではないのか 良い点 同じ
OSS‧セルフホスト思想。標準準拠の OAuth / OIDC サーバとして堅実。 でも 「認証サーバを別に⽴てる」思想で、アプリ組み込み型ではない。2FA / organization 級のプラグイン網羅もない。 → Better Auth なら: アプリのコードベース内で完結し、プラグインで機能を盛れる。
09 — 軸① AI が認証を書く なぜコードベース型 OSS は AI と相性がいいのか
AI が読める AI が⽣成できる AI が規約に沿える auth.ts‧スキーマ‧呼び出し箇所がリポジトリ内 にある 設定からテーブル定義を機械的に導出(CLI) 公式 Skills / ドキュメントを参照させられる SaaS は管理画⾯の「外」に実体があり、AI に渡せる⼿掛かりが少ない。公式の AI 向け4リソース: リソース 何か いつ使うか Ask AI in docs ドキュメント内で AI に直接質問する UI 仕様をその場で確認 llms.txt docs 全体を LLM 向けに構造化したテキスト ⽂脈をまとめて渡す ドキュメント MCP 検索‧例‧セットアップ補助を MCP で提供 エディタから最新 docs を引く Skills 規約‧安全パターンを教えるエージェントスキル 作法どおり実装させる
09 — 軸① AI が認証を書く CLI — ⼈間が(AI も)スキーマを⼿書きしない -/
auth.ts — プラグインを足すだけ -/ テーブル定義は書かない import { organization, twoFactor } from "better-auth/plugins"; export const auth = betterAuth({ generate database: -* adapter -/, emailAndPassword: { enabled: true }, ↓ DB レイヤで出⼒先が変わる plugins : [organization(), twoFactor()], }); npx @better-auth/cli@latest generate npx @better-auth/cli@latest migrate Prisma Drizzle Kysely schema.prisma schema.ts schema.sql organization → 組織/メンバー/招待のテーブル、twoFactor → 2FA カラムが ⾃動で追従。フラグ: --output / --config / --yes。
09 — 軸① AI が認証を書く ドキュメント MCP — AI に「最新の正解」を引かせる
Cursor / Claude Code / Open Code → mcp.better-au th.com/mcp → 公式 docs の最新 npx auth@latest mcp --cursor npx auth@latest mcp --claude-code npx auth@latest mcp --open-code # フラグ無し → 対応ターゲット一覧 認証機能としての MCP プラグイン(→ 6-10)とは別物 — こちらは「ドキュ メントを引くための MCP」。AI の古い記憶ではなく公式最新を参照させ る。 npx auth@latest mcp
09 — 軸① AI が認証を書く 公式 Skills — AI に「作法」を守らせる
SKILL.md 等のポータブル指⽰ファイルで、規約‧安全パターン‧ 「docs のどこを⾒るか」をエージェントに教える。公式パックは better-auth/skills。 npx skills add better-auth 規約をプロンプトに毎回書く代わりに固定 →「それっぽいが間違って いる」認証コードの事故を減らす。認証はミスがそのまま脆弱性になる 領域。
09 — 軸① AI が認証を書く llms.txt と Ask AI in
docs llms.txt Ask AI in docs docs 全体を LLM 向け構造化テキストで公開。 docs サイト上の質問 UI。ページを横断して探さず、その場で 解決。 better-auth.com/llms.txt # 索引 /llms.txt/docs/<path>.md # 各ページ HTML スクレイピング不要 — ページ単位の Markdown を直接コンテ キストへ。 軸①の中では最も軽量な⼊⼝。
09 — 軸① AI が認証を書く 軸①のまとめ — 4要素が1つの状態へ収束する CLI MCP‧llms.txt
Skills Ask AI スキーマ⾃動化 最新ドキュメント供給 作法の矯正 その場の疑問 ↓ 「AI が、正しい⽂脈で、規約どおりに、 認証コードを書ける」状態。 前提 = 認証がコードとして⼿元にあること。