Device Fingerprint
Last updated
This page explains how the device fingerprint that tokens are bound to is generated, where it is checked, and how detection actually behaves.
Generation
CreateFingerprint() (src/CreateFingerprint.ts) builds a JSON object from these four values and takes its SHA-256 hex digest:
| Field | Source |
|---|---|
os |
User-Agent match |
browser |
User-Agent match |
device |
User-Agent match |
deviceId |
X-Device-ID header → req.body.deviceId → "Unknown" |
When req.session.fp exists (for example, stored yourself with express-session), every API uses it instead of recomputing.
Detection Rules
Matching runs top to bottom and the first hit wins:
| Field | Order |
|---|---|
os |
Windows → Macintosh|Mac OS X → Linux → Android → iPhone|iPad|iPod → Unknown_OS |
browser |
Edge|Edg → Firefox → Chrome → Safari → Opera|OPR → Unknown_Browser |
device |
iPad → iPhone|iPod|Android.*Mobile|BlackBerry|IEMobile|Opera Mini → Desktop |
Because matching stops at the first hit, some results are counterintuitive:
| User-Agent | Actual result | Why |
|---|---|---|
| Android | os: Linux |
Android UAs contain Linux, which is checked before Android |
| iPhone / iPad | os: MacOS |
iOS UAs contain like Mac OS X |
| Opera | browser: Chrome |
Opera UAs contain Chrome |
These values only feed the hash; binding works as long as the same device produces the same result each time.
Where It Is Checked
| When | Result on mismatch |
|---|---|
fp in a valid Access Token |
isError: true |
fp decoded from an expired Access Token |
isError: true |
fp in Redis refresh data |
isError: false (guest) |
Related: Token Transport, Client Integration