Skip to content

Server Time Security

The countdown timer now uses server-based timestamps to prevent client-side time manipulation. This ensures that promotional deadlines cannot be bypassed by users changing their system clock.

  • Endpoint: GET /api/time
  • Response: { serverTime: number, requestTime: number | null }
  • Cache Headers: no-store, no-cache to ensure fresh timestamps
  • Security: No client input processing, returns authoritative server time

The CountdownTimer component implements a sophisticated time synchronization system:

  • On page load, fetches server time immediately
  • Calculates network latency (round-trip time)
  • Compensates for latency by adding half the round-trip time
  • Stores the offset between server and client time
  • Automatically resyncs every 5 minutes
  • Prevents long-running sessions from drifting
  • Non-blocking: countdown continues during resync
getCurrentTime() = Date.now() + serverTimeOffset;
  • Server time is the single source of truth
  • Client time is only used as a base for offset calculation
  • Cannot be manipulated without compromising the server
  • Measures round-trip time for each request
  • Assumes symmetric latency (reasonable for most networks)
  • Adds half the RTT to server time for accuracy
  • If server time fetch fails, logs error and continues
  • Prevents countdown from breaking due to network issues
  • Console logs provide debugging information
  • Resyncs every 5 minutes to prevent drift
  • Ensures long-running sessions stay accurate
  • Background sync doesn’t interrupt countdown display
  1. Open DevTools Console and note the initial countdown
  2. Change system time forward by 1 hour
  3. Observe: Countdown should NOT skip ahead
  4. Check console for sync logs: [Countdown] Server time synced. Offset: XXX ms
  5. Refresh page: Countdown should show correct time from server
// Test server time endpoint
fetch('/api/time')
.then((r) => r.json())
.then((data) => {
console.log('Server time:', new Date(data.serverTime));
console.log('Client time:', new Date());
console.log('Difference (ms):', data.serverTime - Date.now());
});
Request Start (Client) ─────►
Server Processing
Response Received (Client) ◄──────
Round Trip Time = Response Time - Request Time
Network Latency (one way) ≈ RTT / 2
Estimated Server Time = Server Time + (RTT / 2)
Server Time Offset = Estimated Server Time - Client Time

The system checks if current time minus last sync time exceeds the sync interval:

if (clientTime - lastSyncTime > SYNC_INTERVAL) {
syncServerTime(); // Non-blocking async resync
}
  1. Network Latency Accuracy: Assumes symmetric latency. In reality, request and response times may differ.
  2. Failover to Client Time: If server is unreachable, falls back to client time (with console error).
  3. 5-Minute Sync Interval: Long enough to reduce server load, but short enough to catch major time changes.
  • Add visual indicator when server sync fails
  • Implement exponential backoff for failed sync attempts
  • Use multiple sync samples to improve accuracy
  • Add server-side deadline validation for purchases
  • Implement NTP-style time synchronization algorithm
  1. Always validate deadlines on the server when processing purchases
  2. Never trust client-side countdown for business logic
  3. Log suspicious activities (e.g., multiple failed syncs)
  4. Rate limit the /api/time endpoint to prevent abuse
  5. Use HTTPS to prevent man-in-the-middle time manipulation