feat(auth): hide Google button when OAuth env is missing
- Export enabledSocialProviders from @ketopath/auth: ['google'] when GOOGLE_CLIENT_ID/SECRET are both set, [] otherwise - sign-in and sign-up pages read enabledSocialProviders server-side and pass googleEnabled to their forms; the divider and button disappear when false - No changes to the Better Auth instance — the Google provider is still conditionally registered, this just keeps the UI honest about it docs/runbooks/google-oauth-setup.md walks through the Google Cloud Console flow end-to-end (project, consent screen, credentials, redirect URIs, env injection, verification, troubleshooting, prod considerations). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
c27e807c43
commit
646b98cccf
7 files changed
+180
-48
No files matched your search
@@ -1,3 +1,4 @@
|
||||
import { enabledSocialProviders } from '@ketopath/auth';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { setRequestLocale } from 'next-intl/server';
|
||||
|
||||
@@ -13,7 +14,7 @@ export default function SignInPage({ params: { locale } }: { params: { locale: s
|
||||
<h1 className="text-3xl font-bold tracking-tight">{t('title')}</h1>
|
||||
<p className="text-sm text-slate-600">{t('subtitle')}</p>
|
||||
</header>
|
||||
<SignInForm />
|
||||
<SignInForm googleEnabled={enabledSocialProviders.includes('google')} />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { useState, type FormEvent } from 'react';
|
||||
|
||||
import { authClient } from '@/lib/auth-client';
|
||||
|
||||
export function SignInForm() {
|
||||
export function SignInForm({ googleEnabled }: { googleEnabled: boolean }) {
|
||||
const t = useTranslations('Auth.SignIn');
|
||||
const router = useRouter();
|
||||
const [email, setEmail] = useState('');
|
||||
@@ -82,23 +82,27 @@ export function SignInForm() {
|
||||
{pending ? t('submitting') : t('submit')}
|
||||
</button>
|
||||
</form>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-slate-200" />
|
||||
</div>
|
||||
<div className="relative flex justify-center">
|
||||
<span className="bg-white px-2 text-xs uppercase tracking-wider text-slate-500">
|
||||
{t('or')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleGoogle}
|
||||
className="w-full rounded-md border border-slate-300 bg-white px-5 py-2.5 text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50"
|
||||
>
|
||||
{t('google')}
|
||||
</button>
|
||||
{googleEnabled ? (
|
||||
<>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-slate-200" />
|
||||
</div>
|
||||
<div className="relative flex justify-center">
|
||||
<span className="bg-white px-2 text-xs uppercase tracking-wider text-slate-500">
|
||||
{t('or')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleGoogle}
|
||||
className="w-full rounded-md border border-slate-300 bg-white px-5 py-2.5 text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50"
|
||||
>
|
||||
{t('google')}
|
||||
</button>
|
||||
</>
|
||||
) : null}
|
||||
<p className="text-center text-sm text-slate-600">
|
||||
{t.rich('noAccount', {
|
||||
link: (chunks) => (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { enabledSocialProviders } from '@ketopath/auth';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { setRequestLocale } from 'next-intl/server';
|
||||
|
||||
@@ -13,7 +14,7 @@ export default function SignUpPage({ params: { locale } }: { params: { locale: s
|
||||
<h1 className="text-3xl font-bold tracking-tight">{t('title')}</h1>
|
||||
<p className="text-sm text-slate-600">{t('subtitle')}</p>
|
||||
</header>
|
||||
<SignUpForm />
|
||||
<SignUpForm googleEnabled={enabledSocialProviders.includes('google')} />
|
||||
<p className="text-xs text-slate-500">{t('disclaimer')}</p>
|
||||
</main>
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useState, type FormEvent } from 'react';
|
||||
|
||||
import { authClient } from '@/lib/auth-client';
|
||||
|
||||
export function SignUpForm() {
|
||||
export function SignUpForm({ googleEnabled }: { googleEnabled: boolean }) {
|
||||
const t = useTranslations('Auth.SignUp');
|
||||
const router = useRouter();
|
||||
const [name, setName] = useState('');
|
||||
@@ -95,23 +95,27 @@ export function SignUpForm() {
|
||||
{pending ? t('submitting') : t('submit')}
|
||||
</button>
|
||||
</form>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-slate-200" />
|
||||
</div>
|
||||
<div className="relative flex justify-center">
|
||||
<span className="bg-white px-2 text-xs uppercase tracking-wider text-slate-500">
|
||||
{t('or')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleGoogle}
|
||||
className="w-full rounded-md border border-slate-300 bg-white px-5 py-2.5 text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50"
|
||||
>
|
||||
{t('google')}
|
||||
</button>
|
||||
{googleEnabled ? (
|
||||
<>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-slate-200" />
|
||||
</div>
|
||||
<div className="relative flex justify-center">
|
||||
<span className="bg-white px-2 text-xs uppercase tracking-wider text-slate-500">
|
||||
{t('or')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleGoogle}
|
||||
className="w-full rounded-md border border-slate-300 bg-white px-5 py-2.5 text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50"
|
||||
>
|
||||
{t('google')}
|
||||
</button>
|
||||
</>
|
||||
) : null}
|
||||
<p className="text-center text-sm text-slate-600">
|
||||
{t.rich('haveAccount', {
|
||||
link: (chunks) => (
|
||||
|
||||
Reference in new issue
Block a user