Un JWT est une petite chose à la portée immense. C'est la preuve d'identité entre vos services, et l'algorithme qui le signe est souvent la partie d'un système la plus lente à changer, car chaque émetteur et chaque vérificateur doivent évoluer en même temps. C'est pourquoi il vaut la peine de savoir que l'option existe avant même d'en avoir besoin.
sgcWebSockets 2026.10 ajoute au client et au serveur JWT les algorithmes JWT post-quantiques de la RFC 9964 : ML-DSA-44, ML-DSA-65 et ML-DSA-87. Ils se placent à côté de HS, RS et ES comme trois valeurs supplémentaires de la même propriété, et tout le reste de votre jeton reste inchangé.
Émettre un jeton
Choisissez l'algorithme dans l'en-tête, donnez au composant une clé privée, puis signez :
oJWT := TsgcHTTP_JWT_Client.Create(nil);
oJWT.JWTOptions.Header.alg := jwtMLDSA65;
oJWT.JWTOptions.Algorithms.MLDSA.PrivateKey.Text := vPrivatePEM;
oJWT.JWTOptions.Payload.iss := 'my-service';
oJWT.JWTOptions.Payload.sub := 'user-1';
vToken := oJWT.Sign;
La clé privée est un PEM PKCS#8 ordinaire. Les trois formes définies par la RFC 9881 sont lues, de sorte qu'une clé stockée comme la graine de 32 octets, comme la clé étendue, ou sous les deux formes, fonctionne dans tous les cas.
Valider un jeton
Côté serveur, la forme est la même, avec la clé publique et la famille activées :
oServer := TsgcHTTP_JWT_Server.Create(nil);
oServer.JWTOptions.Algorithms.MLDSA.Enabled := True;
oServer.JWTOptions.Algorithms.MLDSA.PublicKey.Text := vPublicPEM;
if oServer.Validate(vToken, vHeader, vPayload, vError) then
ShowMessage(vPayload);
Chaque famille est activée indépendamment, de sorte qu'un déploiement qui n'émet que des jetons ML-DSA peut désactiver les autres, et un jeton arrivant avec un alg réglé sur autre chose est refusé plutôt que vérifié.
Le jeu de paramètres doit correspondre
Il y a une règle dans la RFC 9964 qui mérite d'être formulée explicitement, car c'est l'erreur qui passerait autrement inaperçue : la clé doit appartenir au jeu de paramètres que nomme alg. Une clé qui ne correspond pas est refusée. Signer avec la mauvaise lève une exception, et valider avec la mauvaise renvoie faux plutôt que de lever une exception, de sorte qu'un attaquant ne peut rien apprendre de cette différence.
Les clés en tant que JSON Web Keys
La RFC 9964 enregistre un type de clé pour ces algorithmes, AKP, et la bibliothèque sait le lire et l'écrire, ce qui est exactement ce qu'il faut quand les clés sont publiées sur un point de terminaison JWKS plutôt que déposées dans un fichier :
uses
sgcHTTP_JWT_MLDSA;
var
vJWK, vPublicPEM, vPrivatePEM: string;
begin
// {"kty":"AKP","alg":"ML-DSA-65","pub":"...","priv":"..."}
vJWK := sgcMLDSA_ExportPrivateJWK(mldsa65, oSeed);
// and back again, as the PEM the components read
sgcMLDSA_ImportJWKAsPEM(vJWK, vPublicPEM, vPrivatePEM);
end;
Le membre privé est la graine de 32 octets, ce qui correspond à la définition de la RFC, et le lecteur se montre strict à ce sujet : les membres doivent être du base64url canonique de longueur exactement correcte, alg est obligatoire, et lorsqu'une clé privée est présente, elle doit correspondre à la clé publique du même JWK. Un JWK qui échoue à l'un de ces contrôles est rejeté plutôt que chargé à moitié.
Interopérabilité démontrée
Un format de signature n'a d'utilité que si quelqu'un d'autre produit les mêmes octets. Deux vérifications sont livrées sous forme de tests plutôt que d'affirmations :
- Les exemples publiés de la RFC 9964 sont reproduits octet pour octet. Le signataire est la variante déterministe, de sorte que la même clé et la même entrée donnent toujours la même signature, et l'annexe de la RFC devient quelque chose sur lequel on peut faire des assertions.
- Les jetons produits par une implémentation indépendante, en l'occurrence la bibliothèque Python dilithium-py, se valident correctement ici, et les conteneurs de clés écrits à la main d'après la RFC 9881 font l'aller-retour sans être modifiés.
Pendant que nous y étions : un secret HMAC binaire
Une limitation sans rapport a disparu au passage. Les algorithmes HS recevaient leur clé sous forme de texte, alors qu'une véritable clé HMAC est constituée d'octets aléatoires, dont la plupart ne sont pas du texte valide du tout. Il existe désormais une seconde propriété qui accepte la clé en base64url, le même encodage que celui utilisé par le membre k d'un JWK de type oct :
oJWT.JWTOptions.Algorithms.HS.SecretBase64URL := 'AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ...';
Lorsqu'elle est définie, elle prend le pas sur le secret texte, aussi bien côté client que côté serveur.
Des revendications écrites par quelqu'un d'autre
Encore une correction utile à connaître si vous acceptez des jetons d'autres émetteurs. Une chaîne JSON peut être écrite en UTF-8 brut ou avec chaque caractère non-ASCII échappé, et les bibliothèques font des choix différents à ce sujet. Les deux formes se résolvent désormais dans le même texte, de sorte qu'un nom comportant un accent se lit correctement quel que soit l'émetteur qui l'a produit, et un en-tête alg écrit avec des séquences d'échappement est reconnu comme l'algorithme qu'il désigne.
Mise à niveau
Les trois algorithmes s'ajoutent à la fin de la liste existante, de sorte qu'un ordinal déjà stocké conserve sa signification et que rien de ce que vous faites déjà ne change. Signer avec ML-DSA nécessite le pack sgcCrypto, et une compilation qui ne l'inclut pas refuse ces jetons avec un message clair plutôt que d'échouer de façon obscure.
À lire aussi
- Cryptographie post-quantique en Delphi
- Delphi TLS 1.3 sans DLL OpenSSL
- Client JWT Delphi et Serveur JWT Delphi, les bases
À regarder
Il y a une courte vidéo à ce sujet sur la chaîne eSeGeCe.
Des questions, des retours ou besoin d'aide pour migrer ? Contactez-nous — vous recevrez une réponse de la part des personnes qui ont écrit le code.
