Offline Auth Intent
Flux doesn't authenticate anyone — that judgment call stays in your own auth glue. This page covers the one decision every Supabase + Flux app has to get right: telling a real logout apart from a session check that simply couldn't be confirmed because the device is offline.
- @tsworldtech/flux_supabase installed
- A Supabase client constructed with createBrowserClient() or createClient()
- An auth store or equivalent that listens to supabase.auth.onAuthStateChange()
onAuthStateChange fires with session: null. Nothing about that event says whether the user actually signed out or whether the device just can't reach the network right now — but code that treats a null session as a confirmed logout will call flux.clearUserSession() anyway, wiping cached dashboard data that IndexedDB was holding correctly the entire time.navigator.onLine only reflects whether a network interface is up, not whether it actually reaches the internet. A laptop just woken from sleep, or connected to a router with no working WAN, commonly reports navigator.onLine === true for several seconds — sometimes longer — while every real request still fails.
Wire the connectivity aware fetch
createConnectivityAwareFetch() as the client's global.fetch. Every request the Supabase client makes now feeds a shared, evidence based connectivity tracker instead of the browser's unreliable flag — it flips to offline only on a real fetch failure or the browser's offline event, and back to online only once a real request actually succeeds. It also fast fails: once offline is known, further requests reject instantly instead of waiting on the OS's own network timeout, and the very first unproven request is bounded to about 2.5 seconds.Resolve intent inside onAuthStateChange
resolveAuthIntent(event, session) is the single, shared answer to "is this a real logout, or an unverified null session?" It reads from the same tracker the fetch wrapper feeds, so it can never drift out of sync with what the rest of your app believes about connectivity — which is exactly what went wrong when this check was written independently in more than one place.Only clear the session on a confirmed logout
flux.clearUserSession() — a store initializer, an auth listener, wherever your app wires it — should check sessionUnverified (or call isReallyOnline() directly) before purging. When the session is unverified, fall back to the last known cached user ID instead. flux.bootstrap()'s own session continuity guard makes this safe — if the cached ID matches, it hydrates purely from disk with zero network calls, regardless of whether the device is actually online.Reading connectivity elsewhere
navigator.onLine directly. A second, independent connectivity check is how this class of bug creeps back in.You may still see AuthRetryableFetchError and one or more failed token?grant_type=refresh_token requests logged to the console right after a cold, offline boot. This comes from Supabase's own client library performing its one time internal session recovery check at startup — it runs regardless of connectivity and has no public config knob to disable it. createConnectivityAwareFetch() bounds how long that check takes to fail (a few seconds at most instead of whatever the OS's real network stack takes), but it can't remove the check or its console output entirely. This is expected, harmless, and unrelated to what the user sees — cached data still renders immediately from IDB.
For how a resolved user ID drives per tenant caching and cleanup, see core_concepts/multi_tenant_scoping. For general adapter setup, see adapters/supabase.