Exchange InternalsAdvanced18 min read

How Exchanges Track Login Sessions

Technical breakdown of how Binance and Coinbase record every login — IP address, device fingerprint, geolocation, and session lifecycle management.

1

Why Track Logins?

Every reputable exchange records detailed information about every login event. This serves multiple purposes:

  • Fraud detection — A login from Nigeria followed by a withdrawal 2 minutes later, when the user only ever logged in from Italy, is a massive red flag.
  • Account recovery — When a user reports unauthorized access, the exchange can identify exactly when and from where the attacker logged in.
  • Regulatory compliance — KYC/AML regulations require exchanges to maintain access-pattern records. MiCA and the US Bank Secrecy Act both mandate this.
  • User transparency — Binance ("Security → Login Activity") and Coinbase ("Activity → Sessions") expose this data so users can self-audit.

This is not unique to crypto — traditional banks and stock brokers maintain similar records. What makes crypto different is the irreversibility of transactions: once a withdrawal is confirmed on-chain, it cannot be reversed.

2

The Login Sessions Table

Here is the schema used by production-grade exchanges:

CREATE TABLE login_sessions (
  id             UUID PRIMARY KEY,
  user_id        UUID NOT NULL REFERENCES users(id),
  ip_address     INET NOT NULL,
  country        VARCHAR(4),
  city           VARCHAR(100),
  region         VARCHAR(100),
  user_agent     TEXT,
  device_type    VARCHAR(20),
  os             VARCHAR(50),
  browser        VARCHAR(50),
  status         VARCHAR(16) DEFAULT 'active',
  is_current     BOOLEAN DEFAULT TRUE,
  created_at     TIMESTAMPTZ DEFAULT NOW(),
  last_active_at TIMESTAMPTZ DEFAULT NOW(),
  expires_at     TIMESTAMPTZ,
  revoked_at     TIMESTAMPTZ
);

What each field captures: - ip_address — Public IP extracted from X-Forwarded-For or X-Real-IP headers behind a load balancer. - country/city/region — Resolved server-side using MaxMind GeoIP2 database (IP-to-location lookup, not GPS). - user_agent — Raw HTTP header, parsed into device_type, os, and browser using libraries like ua-parser-js. - status — Lifecycle tracking: 'active', 'expired', 'revoked' (manually logged out or admin-terminated).

3

IP Geolocation

When a user logs in, the server resolves their IP to a geographic location:

1. IP extraction: ``typescript const ip = req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || req.headers.get('x-real-ip') || '127.0.0.1'; ``

2. Geolocation lookup (MaxMind GeoIP2, ~70MB offline DB): ``typescript import maxmind from 'maxmind'; const geo = await maxmind.open('GeoLite2-City.mmdb'); const result = geo.get(ip); // result.country.iso_code → 'IT' // result.city.names.en → 'Milan' ``

Accuracy: City-level ~60-80%, country-level ~99%. VPN/Tor users show the exit node's location.

Binance displays login history with: Date, IP Address, Device, Location, Status. They also send email alerts for logins from new IPs or new countries.

Coinbase shows "Active Sessions" with device name, location, last active time, and per-session "Sign Out" button. They use device trust scoring — a known device on a known network gets less friction.

4

Suspicious Login Detection

Exchanges run automated detection rules on every login:

Rule-based detection: - New IP — First time this IP seen for this user → flag for review. - New country — Login from a new country → email alert + potential 2FA re-verification. - Impossible travel — Login from Italy, then Japan 30 minutes later → account lock. - Tor/VPN exit node — IP matches known Tor relays or VPN endpoints → heightened scrutiny. - Rate limiting — More than 5 failed attempts in 10 minutes → temporary IP ban + account lockout.

Implementation (PostgreSQL view): ``sql CREATE VIEW v_suspicious_logins AS SELECT ls.*, CASE WHEN ls.ip_address NOT IN ( SELECT DISTINCT ip_address FROM login_sessions prev WHERE prev.user_id = ls.user_id AND prev.id != ls.id ) THEN TRUE ELSE FALSE END AS is_new_ip, CASE WHEN ls.country NOT IN ( SELECT DISTINCT country FROM login_sessions prev WHERE prev.user_id = ls.user_id AND prev.id != ls.id ) THEN TRUE ELSE FALSE END AS is_new_country FROM login_sessions ls WHERE ls.created_at > NOW() - INTERVAL '30 days'; ``

Binance implements a 24-hour withdrawal lock when a new device or IP is detected. They require re-entering 2FA for any withdrawal from an unrecognized session.

5

Session Lifecycle Management

Sessions are not permanent. Exchanges implement strict lifecycle rules:

Expiration: - Web sessions: 7 days (Binance), 30 days (Coinbase) of inactivity. - API sessions: Based on API key expiry, no implicit timeout. - Mobile: Longer-lived sessions with biometric re-authentication.

Revocation: Users can manually revoke sessions from security settings. When revoked, the JWT is added to a blocklist (Redis, O(1) lookup on every request).

Force logout all: Triggered by critical events: - Password change - 2FA enable/disable - Account compromise detected

Token invalidation: JWT tokens are stateless, so exchanges use a Redis blocklist of revoked token IDs (JTI claim). Every API route checks this blocklist. The TTL on each entry matches the JWT's remaining lifetime.

// On password change, revoke all sessions except current
await pool.query(
  'UPDATE login_sessions SET status = $1, revoked_at = NOW() WHERE user_id = $2 AND id != $3 AND status = $4',
  ['revoked', userId, currentSessionId, 'active']
);

Practice in a risk-free environment

Apply the concepts using virtual funds and live market data. NexChange is an educational simulation, not a real-money exchange.

Continue learning