From 2fcbea3478e89a1cc10e7ec48c66481a662c013c Mon Sep 17 00:00:00 2001 From: pablonete Date: Wed, 24 Jun 2026 18:39:13 +0200 Subject: [PATCH] Fix magic link first-load redirects Ensure URL magic-link tokens are used immediately on first load and delay protected remote data fetches until the access session has been verified, preventing staff pages from redirecting home before auth resolves. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/access/magic-links.ts | 17 +++++++++++++++-- src/contexts/DataLayerContext.tsx | 12 ++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/access/magic-links.ts b/src/access/magic-links.ts index 68e8b20..fe5aa9d 100644 --- a/src/access/magic-links.ts +++ b/src/access/magic-links.ts @@ -48,13 +48,26 @@ export function getStoredMagicLinkToken() { return window.sessionStorage.getItem(magicLinkTokenStorageKey) ?? undefined; } +function getUrlMagicLinkToken() { + if (typeof window === 'undefined') { + return undefined; + } + + const url = new URL(window.location.href); + return url.searchParams.get('token')?.trim() || undefined; +} + +export function getActiveMagicLinkToken() { + return getUrlMagicLinkToken() ?? getStoredMagicLinkToken(); +} + export function clearMagicLinkSession() { window.sessionStorage.removeItem(magicLinkTokenStorageKey); } export function initializeMagicLinkSession() { const url = new URL(window.location.href); - const token = url.searchParams.get('token')?.trim(); + const token = getUrlMagicLinkToken(); if (!token) { return; @@ -85,7 +98,7 @@ export function resolveBuiltInMagicLink(token: string | undefined) { } export function magicLinkRequestHeaders(): Record { - const token = getStoredMagicLinkToken(); + const token = getActiveMagicLinkToken(); return token ? { 'X-Access-Token': token } : {}; } diff --git a/src/contexts/DataLayerContext.tsx b/src/contexts/DataLayerContext.tsx index d313661..d74e65d 100644 --- a/src/contexts/DataLayerContext.tsx +++ b/src/contexts/DataLayerContext.tsx @@ -36,7 +36,7 @@ import { } from '../data/data-model'; import { clearMagicLinkSession, - getStoredMagicLinkToken, + getActiveMagicLinkToken, resolveBuiltInMagicLink, } from '../access/magic-links'; import { @@ -190,7 +190,7 @@ function getInitialMagicLinkUser(isRemoteDataLayer: boolean): CurrentUser | unde return undefined; } - const builtInMagicLink = resolveBuiltInMagicLink(getStoredMagicLinkToken()); + const builtInMagicLink = resolveBuiltInMagicLink(getActiveMagicLinkToken()); if (!builtInMagicLink) { return undefined; @@ -226,7 +226,7 @@ export function DataLayerProvider({ children }: PropsWithChildren) { ); const [accessSessionStatus, setAccessSessionStatus] = useState(() => - getStoredMagicLinkToken() + getActiveMagicLinkToken() ? isRemoteDataLayer ? { state: 'loading' } : getInitialMagicLinkUser(isRemoteDataLayer) @@ -247,7 +247,7 @@ export function DataLayerProvider({ children }: PropsWithChildren) { }; useEffect(() => { - const token = getStoredMagicLinkToken(); + const token = getActiveMagicLinkToken(); if (!token) { setAccessSessionStatus({ state: 'idle' }); @@ -293,7 +293,7 @@ export function DataLayerProvider({ children }: PropsWithChildren) { }, [isRemoteDataLayer]); useEffect(() => { - if (!isRemoteDataLayer) { + if (!isRemoteDataLayer || accessSessionStatus.state !== 'ready') { return; } @@ -302,7 +302,7 @@ export function DataLayerProvider({ children }: PropsWithChildren) { .catch((error) => { console.error('Unable to load remote event data.', error); }); - }, [isRemoteDataLayer]); + }, [accessSessionStatus.state, isRemoteDataLayer]); const persistRemoteSnapshot = (snapshotPromise: Promise) => { snapshotPromise.then(applyRemoteSnapshot).catch((error) => {