Le contexte
Pour un admin durci, j'ai lié le token JWT à une empreinte navigateur (fingerprint) pour limiter le vol de token. À chaque requête, on revérifie l'empreinte.
Le symptôme
Des utilisateurs déconnectés au bout de quelques minutes, de façon aléatoire. Token pourtant non expiré.
La cause
Le fingerprint incluait des composants instables :
// Mauvais : ces valeurs bougent
const fp = hash([
  navigator.userAgent,
  window.innerWidth + 'x' + window.innerHeight, // change au resize !
  navigator.language,
]);
innerWidth/innerHeight change au moindre redimensionnement → le hash ne correspond plus → rejet.
La solution
Ne garder que des composants stables, et vérifier avec tolérance :
const fp = hash([
  navigator.userAgent,
  navigator.language,
  screen.width + 'x' + screen.height, // resolution ecran, pas la fenetre
  navigator.platform,
]);
public function isFingerprintValid(array $tokenFp, array $requestFp): bool
{
    foreach (['ua', 'platform'] as $key) {
        if (($tokenFp[$key] ?? null) !== ($requestFp[$key] ?? null)) {
            return false;
        }
    }
    return true; // les composants secondaires ne bloquent pas
}
Ce que je retiens
  • Un fingerprint = uniquement des composants stables.
  • Égalité stricte sur des données volatiles = bugs aléatoires garantis.
  • Le fingerprint complète, il ne remplace pas, les bonnes pratiques JWT.