驗證
此應用程式執行自己的 Better Auth,位於 /api/auth/*,並透過 genericOAuth 外掛與共享的 Grok 驗證代理 (auth.grok.me) 聯合。此範本已接上 Google 和 X。
支援的登入方式 — 僅使用這三種,其他皆不支援:Google、X 以及電子郵件/密碼。 無其他社交/OAuth 提供者(GitHub、Apple、Discord 等)、無魔法連結、金鑰、一次性密碼、簡訊或匿名登入。請勿在 GROK_PROVIDERS 中新增條目。方法細節及電子郵件/密碼開關(僅編輯 src/lib/auth/email-password.ts):references/sign-in-methods.md。
例外 — 閘道檢視者已登入;切勿為他們呈現登入/重新驗證按鈕。連接器 / 應用程式資料應用程式:僅有閘道「使用 Grok 繼續」,無 Google/X 按鈕:references/grok-identity.md。
登入預設為關閉 — 範本附帶 .grok/app-env.json,內容為 {"VITE_AUTH_ENABLED": "false"},因此僅在需求要求時才新增帳戶(AGENTS.md §0.5)。將其開啟的步驟如下「開啟登入功能」。
一旦開啟,登入是真實的 — 包括在沙盒即時預覽中。 請勿建立示範/模擬/硬編碼使用者。預覽:彈出式視窗 + 內建預覽用戶端;部署後:每個應用程式用戶端 + DATABASE_URL + 零點擊閘道登入(references/prewired-and-env.md)。
當關閉時(VITE_AUTH_ENABLED=false),會回傳一個開發者使用者,以便非驗證應用程式能在沒有已登入訪客的情況下呈現 — 僅限開發與預覽。部署後,此旗標由平台設定(永遠為 "true"),因此 requireUserId 會拒絕所有訪客 — 驗證關閉的應用程式不會使用它或 authMiddleware。
所有內容都已預先安裝並預先接線在 src/lib/auth/ 中 — 請勿執行 npm install;better-auth 是唯一的驗證套件(絕非 @neondatabase/*、@stackframe/* 或 @clerk/*)。請勿編輯或重寫 src/lib/auth/ 下的任何檔案 — 尤其是 server.ts — 除非是 email-password.ts 中的單一旗標。每個檔案對應表:references/prewired-and-env.md。
/auth/popup 已由範本的 Vite 外掛處理(vite.config.ts → popup.server.ts):它永遠不會繪製 React 應用程式。請勿建立 src/routes/auth/popup.tsx(或該路徑下的任何 React 頁面 / 用戶端 OAuth)— 這會在彈出式視窗中顯示完整的應用程式,這是常見的失敗模式。
永遠不要在沙盒中編寫 .env / .env.local / .env.example:即時預覽需要零環境設定,部署後的應用程式會由平台注入其變數。存在的控制項在 references/prewired-and-env.md 中 — 永遠不要對用戶端暴露非 VITE_ 的變數。
migrations/auth/0001_auth.sql 是 Better Auth 的架構 — 請勿編輯。它位於全域比對的 migrations/ 目錄之外(兩者都不會套用),因此不會套用到沒有登入功能的應用程式;「開啟登入功能」會將其複製上去。
開啟登入功能
執行以下所有步驟 — 僅憑路由本身會呈現停用的分支:
- 旗標: 從
.grok/app-env.json中刪除VITE_AUTH_ENABLED金鑰,然後重新啟動開發伺服器。Vite 在啟動時讀取環境變數,因此熱模組替換無法獲取變更。npm run dev、npm run build和npm run preview都會透過scripts/with-app-env.mjs讀取該檔案,因此預覽和建置輸出會一起切換 — 永遠不要直接啟動 Vite。 - 架構:
cp migrations/auth/0001_auth.sql migrations/0001_auth.sql,然後重新啟動以套用。它透過_migrations中的基本名稱進行追蹤,因此已包含此檔案的資料庫不會重新執行。 - 路由: 新增
src/routes/api/auth/$.ts+src/routes/login.tsx— 兩者皆從references/wiring.md複製(此萬用 API 路由是使/api/auth/*和代理回呼正常運作的關鍵)。 - 登出: 一個沒有退出方式的登入功能是不完整的 — 從
@/lib/auth/gates呈現<UserButton />(會連接signOut();對閘道工作階段隱藏登出按鈕)。 - 現有資料: 將應用程式的伺服器函式包裝在
authMiddleware中(一個驗證關閉的應用程式不應該使用它 — 請參閱neon技能)。在登入功能存在之前的資料列是開發資料:除非使用者另有指示,否則請捨棄並重新建立 — 不要將它們交給第一個登入的人。
開啟後在其上建構
- 登入 / 登出: 使用
@/lib/auth/client中的signIn(providerId)和signOut();GROK_PROVIDERS會呈現按鈕。彈出式視窗、Bearer 權杖移交和請求附加是內部實作 — 無需更動。偏好使用<UserButton />(它會處理待處理和失敗狀態);當部署後,如果伺服器從未確認,signOut()會拒絕 — 請加以捕捉。永遠不要使用authClient.signOut():它會將預覽的 Bearer 權杖附加到所有後續請求,因此訪客會保持登入狀態。 - 讀取使用者:
useCurrentUser()僅供顯示(null表示載入中或已登出,因此永遠不要僅依靠它進行重新導向);請改為檢查useCurrentUserState()的isPending。閘道(SignedIn、SignedOut、SignInGate、RedirectToSignIn、UserButton)位於@/lib/auth/gates。CTA 嚴格規則、骨架動畫和 Cookie SSR 無閃爍:references/session-ui.md。 - 每位使用者的專屬資料(強制性): 每個觸及每位使用者專屬資料的伺服器函式都必須使用預先接線的
authMiddleware,並將每個讀取和寫入作業範圍限定在context.userId— Postgres 驅動程式具有完整的資料庫存取權限,因此沒有其他東西可以限制查詢。保持user_id欄位為TEXT類型;永遠不要信任用戶端提供的使用者 ID;當使用者已登出時,中介層會擲回UnauthorizedError(401)。程式碼和停用模式語意:references/per-user-data.md。 - 安全性模型: 無頭代理、
__Host-cookie +trustedOrigins以及 Fetch-Metadata 同儕隔離已預先接線 — 永遠不要為了讓錯誤消失而削弱它們(references/sign-in-methods.md涵蓋了此模型和「無效來源」修正方法)。