La famille JOSE vous donne deux opérations que l’on confond couramment. Signer prouve l’origine et l’intégrité : n’importe qui peut lire la charge utile, personne ne peut l’altérer sans que cela se voie. Chiffrer cache la charge utile : seul le destinataire peut la lire, et cela ne dit rien à soi seul sur qui l’a produite.
L’erreur qui revient toujours
Un JWT signé n’est pas confidentiel. Sa charge utile est en base64url, pas chiffrée. Quiconque détient le jeton la lit, y compris le navigateur par lequel il est passé et le fichier de journal où il a atterri.
La règle est donc simple : si les revendications ne doivent pas être lues par le porteur, un JWS est le mauvais outil, quel que soit l’algorithme.
Une décision, en trois questions
- Le destinataire doit-il savoir qui l’a émis ? Alors signez.
- Serait-ce un problème que le porteur lise les revendications ? Alors chiffrez.
- Les deux ? Alors signez d’abord, chiffrez le résultat. C’est un jeton imbriqué.
L’ordre compte. Signer un bloc chiffré prouve qui l’a chiffré, pas qui a écrit les revendications. Chiffrer une signature prouve qui a écrit les revendications et les cache d’un même geste, ce qui est presque toujours ce que les gens veulent dire.
Le coût que vous choisissez
Un jeton imbriqué est plus gros, plus lent à produire et plus lent à vérifier, et il demande deux jeux de clés avec deux calendriers de rotation. C’est un coût opérationnel réel. Payez-le quand l’exigence de confidentialité est réelle, pas parce que cela fait plus sûr.
Et il existe une option moins coûteuse qu’on oublie : mettre un identifiant opaque dans un jeton signé et garder la partie sensible sur le serveur. Aucun chiffrement à gérer, et les revendications ne quittent jamais votre côté.
JWT-Framework implémente les trois formes, avec une classe dédiée aux jetons imbriqués.