diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index c467924..1f5b82b 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -1,6 +1,10 @@ import { isOidcConfigured } from "@/lib/auth/oidc"; import { LoginPageClient } from "@/components/LoginPageClient"; +// OIDC env is only available at runtime (Docker). Never prerender this page +// at build time or the SSO button stays permanently hidden. +export const dynamic = "force-dynamic"; + export default function LoginPage() { const authUrl = (process.env.AUTH_URL || "").replace(/\/$/, ""); const callbackUrlHint = authUrl diff --git a/src/components/LoginPageClient.tsx b/src/components/LoginPageClient.tsx index 8679d0f..68e28f4 100644 --- a/src/components/LoginPageClient.tsx +++ b/src/components/LoginPageClient.tsx @@ -1,6 +1,6 @@ "use client"; -import { FormEvent, useState } from "react"; +import { FormEvent, useEffect, useState } from "react"; import { signIn } from "next-auth/react"; import { useRouter, useSearchParams } from "next/navigation"; import { Suspense } from "react"; @@ -11,6 +11,12 @@ type Props = { callbackUrlHint: string; }; +type AuthConfig = { + oidcEnabled: boolean; + oidcName: string; + callbackUrl: string; +}; + function authErrorMessage(code: string | null): string | null { if (!code) return null; switch (code) { @@ -40,6 +46,23 @@ function LoginForm({ oidcEnabled, oidcName, callbackUrlHint }: Props) { authErrorMessage(params.get("error")) ); const [loading, setLoading] = useState(false); + const [runtimeOidc, setRuntimeOidc] = useState(null); + + // Belt-and-suspenders: ask the live API so a stale static shell can't hide SSO + useEffect(() => { + fetch("/api/v1/auth/config") + .then((r) => (r.ok ? r.json() : null)) + .then((data: AuthConfig | null) => { + if (data) setRuntimeOidc(data); + }) + .catch(() => { + /* ignore */ + }); + }, []); + + const showOidc = runtimeOidc?.oidcEnabled ?? oidcEnabled; + const displayName = runtimeOidc?.oidcName || oidcName; + const redirectHint = runtimeOidc?.callbackUrl || callbackUrlHint; async function onSubmit(e: FormEvent) { e.preventDefault(); @@ -97,19 +120,19 @@ function LoginForm({ oidcEnabled, oidcName, callbackUrlHint }: Props) { - {oidcEnabled && ( + {showOidc && ( <>

IdP redirect URI must be exactly:
- {callbackUrlHint} + {redirectHint}

)}