diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 1b146b9..6cf62ac 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -105,7 +105,13 @@ api.use("*", resolveStaffMiddleware); // Better-Auth handler — mounted as sub-app to handle all /api/auth/* routes // authMiddleware and resolveStaffMiddleware both skip /api/auth/ paths const authRouter = new Hono(); -authRouter.all("/*", (c) => getAuth().handler(c.req.raw)); +authRouter.all("/*", (c) => { + try { + return getAuth().handler(c.req.raw); + } catch { + return c.json({ error: "Authentication not configured" }, 503); + } +}); api.route("/auth", authRouter); // ── Role guards ──────────────────────────────────────────────────────────────── diff --git a/apps/api/src/lib/auth.ts b/apps/api/src/lib/auth.ts index f77dcbf..fc9f2e2 100644 --- a/apps/api/src/lib/auth.ts +++ b/apps/api/src/lib/auth.ts @@ -170,8 +170,6 @@ export async function initAuth(): Promise { const hasGoogle = !!(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET); const hasGitHub = !!(process.env.GITHUB_CLIENT_ID && process.env.GITHUB_CLIENT_SECRET); - const callbackBase = `${BETTER_AUTH_URL}/api/auth/callback`; - // Build Better-Auth instance using resolved config authInstance = betterAuth({ database: drizzleAdapter(db, { @@ -179,6 +177,9 @@ export async function initAuth(): Promise { }), secret: BETTER_AUTH_SECRET, baseURL: BETTER_AUTH_URL, + account: { + storeStateStrategy: "cookie" as const, + }, plugins: [ genericOAuth({ config: [ @@ -205,14 +206,12 @@ export async function initAuth(): Promise { google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, - redirectURI: `${callbackBase}/google`, }, } : {}), ...(hasGitHub ? { github: { clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET!, - redirectURI: `${callbackBase}/github`, }, } : {}), }, diff --git a/apps/api/src/middleware/auth.ts b/apps/api/src/middleware/auth.ts index 1417614..906f505 100644 --- a/apps/api/src/middleware/auth.ts +++ b/apps/api/src/middleware/auth.ts @@ -23,7 +23,6 @@ if (process.env.AUTH_DISABLED === "true") { } export const authMiddleware: MiddlewareHandler = async (c, next) => { - // Better-Auth's own routes handle their own auth (OAuth callbacks, session mgmt) if (c.req.path.startsWith("/api/auth/")) { await next(); return; @@ -37,7 +36,14 @@ export const authMiddleware: MiddlewareHandler = async (c, next) => { return; } - const session = await getAuth().api.getSession({ + let auth; + try { + auth = getAuth(); + } catch { + return c.json({ error: "Authentication not configured" }, 503); + } + + const session = await auth.api.getSession({ headers: c.req.raw.headers, }); diff --git a/apps/web/package.json b/apps/web/package.json index 2cf5416..3c9d044 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -15,7 +15,7 @@ "dependencies": { "@groombook/types": "workspace:*", "@tailwindcss/vite": "^4.2.2", - "better-auth": "^1.0.0", + "better-auth": "^1.5.6", "lucide-react": "^0.577.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index efaefd3..bf34c03 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -23,17 +23,26 @@ import { useSession, signIn } from "./lib/auth-client.js"; function LoginPage() { const [isLoading, setIsLoading] = useState(false); const [providers, setProviders] = useState([]); + const [error, setError] = useState(null); useEffect(() => { fetch("/api/auth/providers") .then((r) => r.json()) .then((data) => setProviders(data.providers ?? [])) .catch(() => setProviders([])); + const params = new URLSearchParams(window.location.search); + const authError = params.get("error"); + if (authError) setError(authError.replace(/_/g, " ")); }, []); const handleSocialLogin = async (provider: string) => { setIsLoading(true); - await signIn.social({ provider, callbackURL: window.location.origin }); + setError(null); + const result = await signIn.social({ provider, callbackURL: window.location.origin }); + if (result?.error) { + setError(result.error.message ?? "Sign-in failed"); + setIsLoading(false); + } }; const isGoogle = providers.includes("google"); @@ -65,6 +74,11 @@ function LoginPage() {

Sign in to continue

+ {error && ( +
+ {error} +
+ )} {isGoogle && (