Skip to content

OCBC 2FA login not restored after page refresh (deployed)

Goal / bug

On the DEPLOYED web app, after completing the OCBC Velocity 2FA handshake (login), a PAGE REFRESH does not return the user to the connected account view β€” the connection appears lost on reload. Find the root cause (session persistence vs status-check-on-mount vs a deployed-only serverless/cookie issue) and where the fix belongs.

Root cause β€” CORRECTED (2026-06-13) + FIXED

The first diagnosis (empty orgId/userId) was a RED HERRING β€” those fields are never consumed by the OCBC API calls (grep of pages/api/ocbc + lib/ocbc found no reads; the calls use accessToken + cookies + e2eeKeys). The REAL cause is a serverless load-once cache: lib/ocbc/velocity-session-store.ts loadSessionsFromFirestore() loads ALL sessions once and sets globalThis.__velocitySessionsLoaded = true, then if (sessionsLoaded) return forever. On Vercel a warm lambda that ran that load BEFORE the 2FA session was written never re-reads it β†’ on refresh a different warm instance reports "not connected" even though the session IS in Firestore. Matches "works right after 2FA, lost on refresh" exactly. FIX (committed): getVelocitySessionAsync / hasValidVelocitySessionAsync now do a direct PER-USER Firestore read (loadOneSessionFromFirestore(userId): doc(userId).get β†’ decrypt β†’ expiry-check β†’ cache) instead of trusting the load-all-once cache. Typecheck clean. Could not browser-verify (needs a live OCBC 2FA session) β€” owner to confirm on deploy. Cosmetic leftover (NOT the bug): orgId/userId still '' at login.ts:148-149 β€” unused, left as-is. expiresAt is 30 min β€” fine for now; widen later if longer sessions are wanted.

Log

  • 2026-06-13 created + investigated. FIRST diagnosis (empty orgId/userId) was WRONG β€” corrected to the load-once session cache. Fixed via per-user Firestore read; typecheck clean. Awaiting a deploy to confirm live.