All files / src client.ts

0% Statements 0/32
100% Branches 1/1
100% Functions 1/1
0% Lines 0/32

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;