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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | "use client"; /** * Better Auth Client for SnapBack * * This creates the client-side auth client that can be used in React components. * * IMPORTANT: Auth routes are in the WEB app (/api/auth/*), NOT the API server. * The client must point to the same origin as the web app for auth to work. */ import { passkeyClient } from "@better-auth/passkey/client"; import { ssoClient } from "@better-auth/sso/client"; import { adminClient, apiKeyClient, magicLinkClient, multiSessionClient, organizationClient, twoFactorClient, usernameClient, } from "better-auth/client/plugins"; import { createAuthClient } from "better-auth/react"; import type { auth } from "./auth"; // Auth baseURL: Points to where Better Auth routes are served // CRITICAL: Must use a CONSISTENT URL for OAuth redirect_uri to match Google Cloud Console! // // Problem: Using window.location.origin causes issues in multi-port development: // - Port 3000: Marketing site (where /api/auth/* routes live) // - Port 3002: Console/Dashboard // - Port 3003: API server // // If user is on :3002 and we use window.location.origin, OAuth redirect_uri becomes // http://localhost:3002/api/auth/callback/google - but Google Cloud Console only has // :3000 configured, causing "Access blocked: This app's request is invalid". // // IMPORTANT: process.env.NEXT_PUBLIC_* doesn't work in this package because it's compiled // by TypeScript, not Next.js. Next.js can only inline env vars in files it processes. // // Solution: Detect localhost development and hardcode port 3000 for auth. // In production, use window.location.origin since all services share the same domain. /** @internal Exported for testing */ export const getAuthBaseUrl = () => { if (typeof window !== "undefined") { const origin = window.location.origin; // Development: Use current origin since auth routes exist on all Next.js instances // Auth routes (/api/auth/*) are served by Next.js regardless of port (3000, 3002, etc.) // This allows dev:console (port 3002) to work without running port 3000 // // Note: OAuth redirects (Google, GitHub) work because: // 1. OAuth redirect_uri is configured server-side in Better Auth config // 2. The redirect happens server-to-server, not through this client config // 3. Session checks (get-session) work on any port if (origin.includes("localhost:") || origin.includes("127.0.0.1:")) { return origin; } // Production: Use same origin (all services on same domain) return origin; } // Server-side rendering fallback return "http://localhost:3000"; }; const authBaseUrl = getAuthBaseUrl(); // Enterprise feature flags (client-side) const ENABLE_SSO = process.env.NEXT_PUBLIC_FEATURE_SSO === "true"; const ENABLE_MULTI_SESSION = process.env.NEXT_PUBLIC_FEATURE_MULTI_SESSION === "true"; // Build plugin array with conditional enterprise plugins const plugins = [ adminClient(), apiKeyClient(), magicLinkClient(), organizationClient(), passkeyClient(), twoFactorClient(), usernameClient(), // Enterprise plugins (conditionally added) ...(ENABLE_SSO ? [ssoClient()] : []), ...(ENABLE_MULTI_SESSION ? [multiSessionClient()] : []), ]; // Create the auth client with all plugins export const authClient = createAuthClient({ baseURL: authBaseUrl, plugins, }); export type { Session } from "better-auth/types"; // Export the inferred type from the auth instance export type AuthClient = typeof authClient; export type Auth = typeof auth; |