diff --git a/src/routes/idaa/(idaa)/+layout.svelte b/src/routes/idaa/(idaa)/+layout.svelte index ed12b434..ebd5f864 100644 --- a/src/routes/idaa/(idaa)/+layout.svelte +++ b/src/routes/idaa/(idaa)/+layout.svelte @@ -112,7 +112,29 @@ $effect(() => { untrack(() => { if (!current_uuid) { - // No UUID in URL — non-Novi path (user/pass or shared passcode sign-in). + // No UUID in URL. Two possible cases: + // + // 1. Non-Novi path (user/pass or shared passcode sign-in) — clear and deny. + // + // 2. Internal SvelteKit navigation within the iframe (e.g. clicking "Meeting Details" + // from the list page). The UUID was on the initial iframe load URL but is NOT + // carried forward on internal links — they only contain the path/event_id. + // In this case the user has a valid TTL-cached Novi session in $idaa_loc and we + // must NOT clear it, or every internal navigation will show "Access Denied". + // + // Distinguish the two by checking if there is an active verified session. + const now = Date.now(); + const has_cached_session = + $idaa_loc.novi_verified && + $idaa_loc.novi_uuid && + $idaa_loc.novi_verified_ts && + now - $idaa_loc.novi_verified_ts < ttl_ms; + if (has_cached_session) { + // Case 2: internal navigation — keep the verified session, nothing to do. + novi_verifying = false; + return; + } + // Case 1: no UUID, no cached session — non-Novi path, deny normally. $idaa_loc.novi_verified = false; novi_verifying = false; return;