From 1a8306f3db826d40e1e1aeeea1d9362d3241e700 Mon Sep 17 00:00:00 2001 From: Edouard Vanbelle Date: Fri, 14 Aug 2026 13:26:21 +0200 Subject: [PATCH] feat(login): prevent login form flash on OIDC callback --- frontend/src/routes/login/+page.svelte | 1046 +++++++++++++----------- 1 file changed, 555 insertions(+), 491 deletions(-) diff --git a/frontend/src/routes/login/+page.svelte b/frontend/src/routes/login/+page.svelte index 3e62f8fd..08161465 100644 --- a/frontend/src/routes/login/+page.svelte +++ b/frontend/src/routes/login/+page.svelte @@ -117,6 +117,16 @@ // config, or the local account is already linked to a different // identity). See docs/plan/oidc-account-linking.md § Auto-link. let loginErrorNotice = $state(null); + // True while we're mid-OIDC-callback and about to redirect into the + // app. Read synchronously at script-init from `?oidc_code=…` so the + // FIRST paint suppresses the form and shows a loader instead — + // without this the SPA briefly renders the empty username/password + // fields between the IdP redirect and the exchange-then-goto, + // making it look like the login screen "flashed." Cleared in + // onMount if the exchange fails so the normal form takes over. + let willRedirect = $state( + typeof window !== 'undefined' && page.url.searchParams.has('oidc_code') + ); // Refs used by the mode-driven auto-focus effect. Bound with // `bind:this` on the first input of each mode's form so the effect // can focus the "primary" field each time the mode changes without @@ -368,7 +378,10 @@ await goto(resolve(redirectTarget), { replaceState: true }); return; } - // Exchange failed — fall through to the normal login UI. + // Exchange failed — fall through to the normal login UI. Drop + // the loader guard so the form appears; if we leave it true + // the user stares at a spinner indefinitely. + willRedirect = false; } // 2) Existing-session probe: if already authenticated, skip the form. @@ -444,563 +457,588 @@ {t('app.title', 'OxiCloud')} -
-
-