From 595a5e3e04ff5a7e62f4c8626eb61b229f3ba474 Mon Sep 17 00:00:00 2001 From: Leon Serfaty <80597822+silkoserfo@users.noreply.github.com> Date: Fri, 3 Jul 2026 08:26:08 -0400 Subject: [PATCH] feat(auth): hide Google sign-in until OAuth is configured Google social login has no credentials in production, so the "Continue with Google" button (and its divider) errored on click. Gate the button + divider on a new isGoogleConfigured() helper (requires GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET) on both the login and signup pages, and guard the signInWithGoogle action as defense in depth. The button reappears automatically once both env vars are set. Co-Authored-By: Claude Opus 4.8 --- app/(auth)/login/page.tsx | 41 +++++++++++++++++++++----------------- app/(auth)/signup/page.tsx | 41 +++++++++++++++++++++----------------- app/actions/auth.ts | 7 ++++++- lib/auth.ts | 9 +++++++++ 4 files changed, 61 insertions(+), 37 deletions(-) diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx index 4b93b4d..eb89275 100644 --- a/app/(auth)/login/page.tsx +++ b/app/(auth)/login/page.tsx @@ -3,6 +3,7 @@ import Link from "next/link" import { Logo } from "@/components/shared/logo" import { TurnstileWidget } from "@/components/shared/turnstile-widget" import { signIn, signInWithGoogle } from "@/app/actions/auth" +import { isGoogleConfigured } from "@/lib/auth" export const metadata: Metadata = { title: "Sign in", @@ -28,25 +29,29 @@ export default async function LoginPage({
- {/* Google OAuth */} -
- -
+ {isGoogleConfigured() && ( + <> + {/* Google OAuth */} +
+ +
-
-
-
-
-
- or continue with email -
-
+
+
+
+
+
+ or continue with email +
+
+ + )} {/* Error / Success messages */} {error && ( diff --git a/app/(auth)/signup/page.tsx b/app/(auth)/signup/page.tsx index 9b24179..992ac8d 100644 --- a/app/(auth)/signup/page.tsx +++ b/app/(auth)/signup/page.tsx @@ -2,6 +2,7 @@ import Link from "next/link" import { Logo } from "@/components/shared/logo" import { TurnstileWidget } from "@/components/shared/turnstile-widget" import { signUp, signInWithGoogle } from "@/app/actions/auth" +import { isGoogleConfigured } from "@/lib/auth" export default async function SignupPage({ searchParams, @@ -47,25 +48,29 @@ export default async function SignupPage({
- {/* Google OAuth */} -
- -
+ {isGoogleConfigured() && ( + <> + {/* Google OAuth */} +
+ +
-
-
-
-
-
- or sign up with email -
-
+
+
+
+
+
+ or sign up with email +
+
+ + )} {error && (
diff --git a/app/actions/auth.ts b/app/actions/auth.ts index 0e64a44..7762971 100644 --- a/app/actions/auth.ts +++ b/app/actions/auth.ts @@ -3,7 +3,7 @@ import { redirect } from "next/navigation" import { headers } from "next/headers" import { APIError } from "better-auth/api" -import { auth } from "@/lib/auth" +import { auth, isGoogleConfigured } from "@/lib/auth" import { verifyTurnstile } from "@/lib/turnstile" const APP_URL = process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000" @@ -77,6 +77,11 @@ export async function signIn(formData: FormData) { } export async function signInWithGoogle() { + // Defense in depth: the auth pages hide the Google button when it isn't + // configured, but guard the action too in case it's POSTed directly. + if (!isGoogleConfigured()) { + redirect(`/login?error=${encodeURIComponent("Google sign-in isn't available right now.")}`) + } let url: string | undefined try { const res = await auth.api.signInSocial({ diff --git a/lib/auth.ts b/lib/auth.ts index d857d91..49d0862 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -116,3 +116,12 @@ export const auth = betterAuth({ ], }) +/** + * Whether Google OAuth is configured. The auth pages hide the "Continue with + * Google" button unless BOTH credentials are present, so users never see a + * social option that can't complete. Mirrors socialProviders.google above. + */ +export function isGoogleConfigured(): boolean { + return Boolean(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET) +} +