diff --git a/app/[locale]/login/page.tsx b/app/[locale]/login/page.tsx index 16d8550..8130da3 100644 --- a/app/[locale]/login/page.tsx +++ b/app/[locale]/login/page.tsx @@ -40,6 +40,7 @@ export default function LoginPage() { const [oauthDiscoveryDone, setOauthDiscoveryDone] = useState(false); const [oauthLoading, setOauthLoading] = useState(false); const [oauthRetryCount, setOauthRetryCount] = useState(0); + const [oauthLocalError, setOauthLocalError] = useState(null); const suggestionsRef = useRef(null); const inputRef = useRef(null); @@ -256,6 +257,17 @@ export default function LoginPage() { const handleOAuthLogin = async () => { if (!oauthMetadata || !oauthClientId) return; + + // PKCE needs Web Crypto (SubtleCrypto.digest). That API is only exposed + // in secure contexts — i.e. HTTPS or localhost. Fail loudly before we + // try to call it so the user sees a fix-this message instead of a + // mystery "crypto.subtle is undefined" TypeError. + if (typeof window === "undefined" || !window.isSecureContext || typeof crypto?.subtle?.digest !== "function") { + setOauthLocalError(t("oauth_error.requires_https")); + return; + } + + setOauthLocalError(null); setOauthLoading(true); const verifier = generateCodeVerifier(); @@ -344,6 +356,13 @@ export default function LoginPage() { )} + {oauthLocalError && ( +
+ +

{oauthLocalError}

+
+ )} + {/* Login Form */}