← All posts

Chaque validation de jeton atteignait notre origine. Désormais, le JWKS vit à la périphérie.

Authagonal·July 20, 2026
authoidcjwkscdncloudflarecachingkey-rotation

Pour valider l'un de nos JWT, un service récupère deux documents publics auprès de l'émetteur : le document de découverte à l'adresse /.well-known/openid-configuration, et le JWKS vers lequel il pointe — l'ensemble des clés publiques avec lesquelles les jetons sont signés. Ce sont les ressources les plus demandées et les moins secrètes que nous servons. Ce sont des clés publiques, publiques par définition, et des métadonnées qui ne changent que lorsque nous effectuons une rotation. Et jusqu'à récemment, chacune de ces récupérations remontait tout le chemin jusqu'à notre origine. Parce que nous sommes multi-locataires, c'était pire que cette phrase ne le laisse entendre.

L'origine effectuait un travail qu'elle n'avait aucune raison de faire

Chaque locataire est son propre émetteur, avec son propre document .well-known et son propre JWKS. Et chaque partie de confiance, chaque serveur de ressources, chaque SDK qui valide un jeton va chercher ces documents — lors d'un démarrage à froid, quand son propre petit cache expire, une fois par instance de service. Multipliez les émetteurs par locataire par les validateurs par service par les défauts de cache, et vous obtenez un déluge de requêtes, qui aboutissent toutes à l'application, toutes pour des documents identiques octet pour octet pour chaque appelant et qui ne changent que lorsque nous effectuons la rotation d'une clé.

C'est le cas d'école de ce qui devrait être mis en cache : public, identique, changeant rarement. Au lieu de cela, l'application produisait des clés publiques, dynamiquement, sur le chemin critique de la validation de jetons de tout le monde. Ces clés n'avaient aucune raison d'être calculées à chaque requête.

Les déporter à la périphérie

Le changement en lui-même est modeste : poser des en-têtes Cache-Control honnêtes sur les réponses de découverte et de JWKS pour que Cloudflare les mette en cache à la périphérie. Désormais, un validateur atteint le point de présence Cloudflare le plus proche, et l'origine sert chaque document environ une fois par PoP et par TTL au lieu d'une fois par validation. La découverte est trivialement cachable — elle ne change presque jamais. Le JWKS est celui auquel il faut réfléchir sérieusement, car le JWKS est le seul document dont le rôle même est de changer exactement au moment où vous effectuez une rotation de clé, et mettre en cache une chose qui doit être fraîche à l'unique instant où elle change, c'est précisément là que l'on se blesse.

Comment un JWKS mis en cache se retourne contre vous

La rotation de clé combinée à un ensemble de clés mis en cache est un piège, et il échoue dans la pire direction possible. Effectuez une rotation vers une nouvelle clé de signature, commencez à émettre des jetons avec elle, et un validateur qui a récupéré le JWKS avant l'apparition de la nouvelle clé détient une copie périmée. Un jeton arrive, porteur de l'identifiant de la nouvelle clé ; le validateur le recherche, ne le trouve pas, et rejette le jeton. Le jeton est parfaitement valide. La signature est authentique. L'utilisateur n'a rien fait de mal. Votre propre cache de périphérie vient de renvoyer un 401 à une connexion légitime.

Remarquez dans quel sens cela échoue. Une clé privée périmée est un non-événement — vous n'avez tout simplement pas encore commencé à utiliser la nouvelle. Un ensemble de clés publiques périmé est une panne que l'on s'inflige à soi-même, et vous avez introduit exprès le cache qui l'a provoquée, pour économiser du trafic vers l'origine. La sûreté de tout le dispositif tient ou s'effondre sur la rotation.

Le schéma sûr pour la rotation

La sûreté réside entièrement dans l'ordonnancement, et cet ordonnancement est l'exact opposé d'une permutation atomique. Trois règles :

  • Publiez avant de signer. La nouvelle clé entre d'abord dans le JWKS, et vous ne signez pas un seul jeton avec elle tant que ce JWKS — nouvel identifiant de clé compris — n'a pas été en ligne à la périphérie pendant au moins un TTL de cache complet. Au moment où un jeton porteur de la nouvelle clé peut atteindre un validateur, l'ensemble de clés en cache du validateur contient déjà la clé.
  • Retirez après expiration, pas au moment de la rotation. L'ancienne clé reste publiée dans le JWKS jusqu'à ce que le dernier jeton qu'elle a jamais signé ait expiré. L'ancienne et la nouvelle coexistent pendant toute la période de recouvrement. Retirez l'ancienne clé au moment où vous effectuez la rotation, et vous laissez en rade chaque jeton encore valide qu'elle a signé.
  • Un TTL plus court que le recouvrement. Le max-age du cache de périphérie, plus une marge pour le décalage d'horloge, doit être plus court que la fenêtre de recouvrement des clés. Le cache a le droit d'être périmé ; il n'a jamais le droit d'être périmé plus longtemps que la fenêtre pendant laquelle les deux clés sont valides. C'est cette seule inégalité qui rend inoffensif un JWKS agressivement mis en cache.

Mis bout à bout, tout cela transforme la rotation en un fondu enchaîné à l'ordre d'exécution fixe : ajouter la nouvelle clé, attendre un TTL que la périphérie et chaque validateur la voient, commencer à signer avec elle, attendre que les anciens jetons arrivent à échéance, puis retirer l'ancienne clé. Chaque étape est sûre face à un cache en retard d'un TTL, car le TTL a été choisi pour être plus petit que toute fenêtre dont un cache pourrait être en retard.

La leçon, factorisée

La mise en cache est généralement une décision de latence. Mettre en cache des clés publiques est une décision d'exactitude, car ce que vous mettez en cache est précisément ce qui décide quels jetons sont authentiques. Vous pouvez tout à fait le placer à la périphérie — vous le devriez, car c'est public et c'est très sollicité — mais seulement une fois que la rotation est exprimée comme un recouvrement ordonné plutôt que comme une permutation, et seulement une fois qu'il est prouvé que le TTL du cache est plus court que ce recouvrement. Faites cela correctement, et les documents les plus sollicités et les plus cachables de votre système d'authentification cessent de toucher votre origine, et personne ne remarque jamais la différence — ce qui est précisément le but recherché.