feat(oidc): reduce amount of page when auto_redirect_to_oidc
This commit is contained in:
@@ -99,6 +99,20 @@ export interface OidcProviders {
|
|||||||
*/
|
*/
|
||||||
require_verified_email?: boolean;
|
require_verified_email?: boolean;
|
||||||
authorize_endpoint?: string;
|
authorize_endpoint?: string;
|
||||||
|
/**
|
||||||
|
* Server-computed: true when the `auto_redirect_if_standalone_oidc`
|
||||||
|
* policy is on AND OIDC is the only working method (see
|
||||||
|
* `AuthApplicationService::auto_redirect_to_oidc`). When true the root
|
||||||
|
* layout guard `window.location.replace`s to `authorize_endpoint`
|
||||||
|
* instead of routing through `/login` — the server-side `/login`
|
||||||
|
* middleware only fires on full HTTP loads, so SPA client-side
|
||||||
|
* navigation to `/login` (root guard, dev via Vite) would otherwise
|
||||||
|
* stall on the login page. Because the flag is gated by the admin's
|
||||||
|
* policy on the SERVER, using it on the client does NOT override the
|
||||||
|
* policy toggle — we're just enacting the same decision on paths the
|
||||||
|
* middleware can't reach.
|
||||||
|
*/
|
||||||
|
auto_redirect_to_oidc?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Public OIDC provider info for the login page. */
|
/** Public OIDC provider info for the login page. */
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
import { ui } from '$lib/stores/ui.svelte';
|
import { ui } from '$lib/stores/ui.svelte';
|
||||||
import { hashUrlToPath } from '$lib/utils/hashRedirect';
|
import { hashUrlToPath } from '$lib/utils/hashRedirect';
|
||||||
import { killLegacyServiceWorker } from '$lib/utils/killLegacyServiceWorker';
|
import { killLegacyServiceWorker } from '$lib/utils/killLegacyServiceWorker';
|
||||||
|
import { getOidcProviders, type OidcProviders } from '$lib/api/endpoints/auth';
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
|
|
||||||
@@ -34,6 +35,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ready = $state(false);
|
let ready = $state(false);
|
||||||
|
// Providers info fetched at boot so the guard below can enact the
|
||||||
|
// SSO-only server-side policy (`auto_redirect_if_standalone_oidc`) on
|
||||||
|
// SPA client-nav paths the middleware in interfaces/web/mod.rs can't
|
||||||
|
// see. The middleware only fires on full HTTP loads to /login; when
|
||||||
|
// the layout guard is about to `goto('/login')` we short-circuit to
|
||||||
|
// the IdP directly if the server tells us to. Null until fetched;
|
||||||
|
// the guard waits for it before deciding.
|
||||||
|
let providers = $state<OidcProviders | null>(null);
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await killLegacyServiceWorker();
|
await killLegacyServiceWorker();
|
||||||
@@ -51,7 +60,9 @@
|
|||||||
const mapped = hashUrlToPath(location.hash);
|
const mapped = hashUrlToPath(location.hash);
|
||||||
if (mapped) await goto(resolve(mapped as Pathname), { replaceState: true });
|
if (mapped) await goto(resolve(mapped as Pathname), { replaceState: true });
|
||||||
}
|
}
|
||||||
await session.load();
|
// Parallel — providers is a public endpoint independent of session state.
|
||||||
|
const [, prov] = await Promise.all([session.load(), getOidcProviders()]);
|
||||||
|
providers = prov;
|
||||||
ready = true;
|
ready = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -60,9 +71,18 @@
|
|||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (!ready) return;
|
if (!ready) return;
|
||||||
const path = page.url.pathname;
|
const path = page.url.pathname;
|
||||||
if (!session.isAuthenticated && !isPublic(path)) {
|
if (session.isAuthenticated || isPublic(path)) return;
|
||||||
void goto(resolve(`/login?redirect=${encodeURIComponent(path)}`), { replaceState: true });
|
|
||||||
|
// SSO-only auto-redirect: mirror what the server-side /login
|
||||||
|
// middleware does for direct HTTP loads. Full-page navigation
|
||||||
|
// (`window.location`) so we hit the OxiCloud backend fresh — that
|
||||||
|
// endpoint 307s to the IdP with a fresh state + PKCE challenge.
|
||||||
|
// `goto()` would keep us in the SPA and never leave.
|
||||||
|
if (providers?.auto_redirect_to_oidc && providers.authorize_endpoint) {
|
||||||
|
window.location.replace(providers.authorize_endpoint);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
void goto(resolve(`/login?redirect=${encodeURIComponent(path)}`), { replaceState: true });
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user