Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | 6x 6x 6x 6x 6x 6x | import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { nextCookies } from "better-auth/next-js";
import { getDb } from "@/lib/db";
import { env, previewTrustedOrigins } from "@/lib/env";
import { user, session, account, verification } from "@/lib/db/schema";
// better-auth `auth` instance — the ONLY auth backend now (NextAuth retired in
// Cutover Pass 2b-i). Mounted at /api/auth; the façade (auth.ts), middleware,
// and UI all read/drive it.
//
// - drizzleAdapter maps better-auth's four core models onto our canonical
// Drizzle tables (`user`/`session`/`account`/`verification`). Pass 2b-ii
// collapsed the old `user`↔`ba_user` split into this single `user` table:
// better-auth OWNS it and every domain FK resolves straight to it — no more
// mirroring bridge.
// - Google is the only supported sign-in method for Adored. Email/password,
// magic-link, and email verification are intentionally not configured.
// - Google creds are optional at construction time so local/test builds boot,
// but a deployment with empty creds has no usable login path.
// - nextCookies() MUST be the LAST plugin: plugins wrap each other like
// middleware, and the cookie-writer must see the final response to attach the
// Set-Cookie that carries the session.
//
// Secret/base URL prefer the better-auth-specific vars, falling back to the
// VALIDATED `env.AUTH_SECRET`/`env.AUTH_URL` (not raw process.env) so a single
// secret can serve both AND preview deploys — which have no explicit AUTH_URL —
// get env.ts's VERCEL_URL-derived base URL instead of `undefined`.
// better-auth rate-limits auth requests per-IP and is ON in production builds.
// The e2e suite runs a production `next start` and creates multiple signed
// session fixtures from a single loopback IP (baseline + per-user authz
// fixtures), which can trip the limiter (429). Disable it only for loopback
// base URLs — real
// deployments (https origin) keep the protection. Host is parsed defensively;
// a malformed URL leaves rate limiting ON (fail-safe).
function isLoopbackBaseUrl(): boolean {
const raw = process.env.BETTER_AUTH_URL ?? env.AUTH_URL;
Iif (!raw) return false;
try {
const host = new URL(raw).hostname;
return host === "localhost" || host === "127.0.0.1" || host === "::1";
} catch {
return false;
}
}
export const auth = betterAuth({
rateLimit: { enabled: !isLoopbackBaseUrl() },
database: drizzleAdapter(getDb(), {
provider: "pg",
schema: {
user,
session,
account,
verification,
},
}),
secret: process.env.BETTER_AUTH_SECRET ?? env.AUTH_SECRET,
baseURL: process.env.BETTER_AUTH_URL ?? env.AUTH_URL,
// Mounted at the default /api/auth (Cutover Pass 2b-i): NextAuth is retired,
// so the [...nextauth] collision is gone and better-auth owns /api/auth. It
// builds all its route + callback URLs from this basePath, so it must match
// the src/app/api/auth/[...all] mount — and the Google callback is therefore
// …/api/auth/callback/google (matches the setup checklist).
basePath: "/api/auth",
// better-auth's default trusted set is exactly [origin(baseURL)]; this ADDS the
// preview branch alias so sign-in works on the URL the PR comment links to. It is
// [] everywhere but preview — production's trusted set is unchanged. See env.ts.
trustedOrigins: previewTrustedOrigins(),
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID ?? "",
clientSecret: process.env.GOOGLE_CLIENT_SECRET ?? "",
},
},
plugins: [
// Keep nextCookies LAST — see note above.
nextCookies(),
],
});
|