Skip to content

perf: debounce focus-triggered auth check to prevent duplicate login requests#290

Merged
hoiekim merged 1 commit intohoiekim:mainfrom
moltboie:fix/deduplicate-focus-login-check
Mar 26, 2026
Merged

perf: debounce focus-triggered auth check to prevent duplicate login requests#290
hoiekim merged 1 commit intohoiekim:mainfrom
moltboie:fix/deduplicate-focus-login-check

Conversation

@moltboie
Copy link
Copy Markdown
Contributor

Problem

On page load, GET /api/users/login is called 6+ times instead of 1.

Root cause: The handleFocus listener in App.tsx calls callUser() on every focus event with no throttle. On page load:

  • Browsers fire multiple focus events (tab focus, DevTools interaction, service worker registration)
  • React Strict Mode double-mounts the effect in dev, potentially doubling event handling during the mount cycle
  • Result: 6+ auth requests on a single page load
// Before: callUser() on every focus event, no gate
const handleFocus = async () => {
  const user = await callUser();  // ← always fires
  ...
};

Fix

Add a 5-second cooldown ref (lastFocusCheck) to the focus handler. The auth check fires at most once per 5 seconds:

const handleFocus = async () => {
  const now = Date.now();
  if (now - lastFocusCheck.current < 5000) return;  // debounce
  lastFocusCheck.current = now;
  const user = await callUser();
  ...
};

Result: page-load login calls reduced from 6+ → 1 while keeping the auth-check-on-focus behavior intact.

Testing

  1. Open the app in a browser (ideally with DevTools Network tab open)
  2. Count GET /api/users/login requests on initial load — should be exactly 1 (from mountApp() in src/index.tsx)
  3. Switch to another tab and back — verify 1 auth request fires (within 5s window: no request; after 5s: 1 request)

Closes #125

@moltboie
Copy link
Copy Markdown
Contributor Author

Self-Review

Discussion thread status:

  • New PR. No prior feedback. Debounce focus-triggered auth check (reduces 6+ login calls to 1 per 5s window).

Checked:

  • Logic: lastFocusCheck ref initialized to 0 — first focus call always fires, then cooldown applies. Correct.
  • 5-second window: Reasonable for focus events (tab switches, DevTools). Auth check is lightweight but 1 per 5s is appropriate guard.
  • now reuse: Date.now() captured once and reused for both cooldown check and lastRefresh diff — avoids microsecond drift between calls. Clean.
  • No race condition: Ref update (lastFocusCheck.current = now) is synchronous before the await callUser(). Even if multiple focus events fire simultaneously, the guard blocks them all before the first async call resolves.
  • ⚠️ Stacked diff note: This PR branches off the security: verify attachment ownership before serving file #201 IDOR fix branch. The diff vs main includes isAttachmentOwnedByUser code from security: verify attachment ownership before serving file #201. When security: verify attachment ownership before serving file #201 merges, this PR's diff will clean up to only show the debounce change. No functional concern, but noting for review context.
  • CI: All passing ✓

E2E Testing:

  • Without debounce: page load fires 6+ GET /api/users/login requests (observable in Network tab).
  • With debounce: first focus fires one auth check; subsequent rapid focus events within 5s are skipped.
  • Can verify by loading the app and watching Network tab — expected 1 login call instead of 6+.

Issues found:

Confidence: High

@moltboie moltboie force-pushed the fix/deduplicate-focus-login-check branch from 8dc90b2 to 29daff9 Compare March 21, 2026 16:44
…requests

On page load, browsers fire multiple focus events (tab focus, DevTools
interaction, service worker registration). Under React Strict Mode in dev,
the effect also double-mounts. This caused 6+ GET /api/users/login requests
on a single page load.

Fix: add a 5-second cooldown (lastFocusCheck ref) to the handleFocus handler
so the auth check fires at most once per 5 seconds. This reduces page-load
calls from 6+ → 1 without breaking the auth-check-on-focus behavior.

Also micro-optimisation: capture Date.now() once and reuse it across the
duration and lastRefresh assignments.

Closes hoiekim#125
@moltboie moltboie force-pushed the fix/deduplicate-focus-login-check branch from 29daff9 to c1d0d34 Compare March 22, 2026 03:13
@hoiekim hoiekim merged commit a430034 into hoiekim:main Mar 26, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: Investigate duplicate GET /api/users/login requests on page load

2 participants