Les jetons web JSON (JWT, prononcés « jots ») constituent un moyen compact et très facilement transportable d’échanger des informations d’identité. La spécification JWT est l’un des fondements essentiels d’OpenID Connect, car elle fournit un jeton d’authentification unique pour l’écosystème OAuth 2.0. Les JWT peuvent également servir eux-mêmes d’identifiants d’authentification et permettent de contrôler l’accès aux API web plus efficacement que les clés d’API traditionnelles.
NGINX Plus R10 et les versions ultérieures peuvent valider directement les JWT. Dans cet article de blog, nous expliquons comment utiliser NGINX Plus comme passerelle d’API, en fournissant une interface à un point de terminaison d’API et en utilisant des JWT pour authentifier les applications clientes.
La prise en charge native des JWT est disponible uniquement dans NGINX Plus, et non dans NGINX Open Source.
Éditeur – Cet article de blog a été mis à jour en décembre 2021 afin d’utiliser la directive auth_jwt_require introduite dans NGINX Plus R25. Pour une présentation détaillée de cette directive, consultez Règles personnalisées de validation des JWT dans l’article de blog annonçant NGINX Plus R25.
NGINX Plus R15 et les versions ultérieures peuvent également contrôler le « flux de code d’autorisation » dans OpenID Connect 1.0, ce qui permet l’intégration avec la plupart des principaux fournisseurs d’identité. Pour plus de détails, consultez Présentation de NGINX Plus R15<.htmlspan>.
Anatomie d’un JWT
Les JWT se composent de trois parties : un en-tête, une charge utile et une signature. Lors de leur transmission, ils se présentent comme ci-dessous. Nous avons ajouté des sauts de ligne pour faciliter la lecture (en réalité, le JWT est une chaîne de caractères unique), ainsi qu’un code couleur pour distinguer les trois parties :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICAgInN1YiI6ICJsYzEiLAogICAgImVtYWlsIjogImxpYW0uY3JpbGx5QG5naW54LmNvbSIsCn0=.VGYHWPterIaLjRi0LywgN3jnDUQbSsFptUw99g2slfcComme illustré, un point ( . ) sépare l’en-tête, la charge utile et la signature. L’en-tête et la charge utile sont des objets JSON encodés en Base64. La signature est chiffrée à l’aide de l’algorithme spécifié par l’en-tête alg, comme nous pouvons le constater en décodant notre exemple de JWT :
Encodé DécodéEn-tête eyJhbGciOiJIUzI1NiIsInR5cCI6Ik pXVCJ9 {Charge utile
"alg": "HS256",
"typ": "JWT"
}ewogICAgInN1YiI6ICJsYzEiLAogICAgImVtYWlsIjogImxpYW0uY3JpbGx5QG5naW54LmNvbSIsCn0= {
"sub": "lc1",
"email": "liam.crilly@nginx.com",
}
La norme JWT définit plusieurs algorithmes de signature. Dans notre exemple, la valeur HS256 désigne HMAC SHA‑256, que nous utilisons pour tous les exemples de JWT de cet article de blog. NGINX Plus prend en charge les HSxxx, RSxxx et ESxxx, qui sont des algorithmes de signature définis dans la norme. La possibilité de signer cryptographiquement les JWT en fait des identifiants d’authentification idéaux.
Le JWT comme clé d’API
Une méthode courante pour authentifier un client d’API (le logiciel client distant qui demande des ressources à l’API) consiste à utiliser un secret partagé, généralement appelé clé d’API. Une clé d’API classique est essentiellement un mot de passe long et complexe que le client envoie dans un en-tête HTTP supplémentaire à chaque requête. Le point de terminaison de l’API autorise l’accès à la ressource demandée si la clé d’API fournie figure dans la liste des clés valides. En général, le point de terminaison de l’API ne valide pas lui-même les clés d’API ; une passerelle d’API se charge plutôt du processus d’authentification et achemine chaque requête vers le point de terminaison approprié. Outre le déport de la charge de calcul, cette approche offre les avantages d’un proxy inverse, tels que la haute disponibilité et la répartition de charge entre plusieurs points de terminaison d’API.

au point de terminaison de l’API
Il est courant d’appliquer des contrôles d’accès et des politiques différents selon les clients d’API. Avec les clés d’API traditionnelles, il faut effectuer une recherche pour associer la clé d’API à un ensemble d’attributs. Effectuer cette recherche à chaque requête a naturellement une incidence sur la latence globale du système. Avec les JWT, ces attributs sont intégrés, ce qui évite d’avoir à effectuer une recherche distincte.
L’utilisation d’un JWT comme clé d’API offre une alternative hautes performances aux clés d’API traditionnelles, en associant une technologie d’authentification conforme aux bonnes pratiques à un schéma normalisé pour l’échange d’attributs d’identité.

Configuration de NGINX Plus en tant que passerelle API d’authentification
La configuration de NGINX Plus pour valider les JWT est très simple.
upstream api_server {
server 10.0.0.1;
server 10.0.0.2;
}
server {
listen 80;
location /products/ {
auth_jwt "Products API";
auth_jwt_key_file conf/api_secret.jwk;
proxy_pass http://api_server;
}
}La première chose à faire est d’indiquer les adresses des serveurs qui hébergent le point de terminaison de l’API dans le bloc upstream. Le bloc location indique que toutes les requêtes adressées à des URL commençant par /products/ doivent être authentifiées. La directive auth_jwt définit le domaine d’authentification qui sera renvoyé (avec un code d’état 401) en cas d’échec de l’authentification.
La directive « auth_jwt_key_file » indique à NGINX Plus comment valider l’élément de signature du JWT. Dans cet exemple, nous utilisons l’algorithme HMAC SHA-256 pour signer les JWT. Nous devons donc créer une clé web JSON dans le fichier conf/api_secret.jwk afin d’y stocker la clé symétrique utilisée pour la signature. Le fichier doit respecter le format décrit dans la spécification JSON Web Key ; notre exemple se présente comme suit :
{"keys":
[{
"k":"ZmFudGFzdGljand0",
"kty":"oct",
"kid":"0001"
}]
}La clé symétrique est définie dans le champ « k » et voici la valeur encodée en Base64URL de la chaîne de caractères en clair « fantasticjwt ». Nous avons obtenu la valeur encodée en exécutant cette commande :
$ echo -n fantasticjwt | base64 | tr '+/' '-_' | tr -d '='Le champ « kty » définit le type de clé comme une clé symétrique (séquence d’octets). Enfin, le champ « kid » (identifiant de clé) définit un numéro de série pour cette clé Web JSON, ici 0001, ce qui nous permet de prendre en charge plusieurs clés dans le même fichier (désigné par la directive « auth_jwt_key_file ») et de gérer le cycle de vie de ces clés ainsi que celui des JWT signés avec celles-ci.
Nous sommes maintenant prêts à émettre des JWT pour nos clients d’API.
Émission d’un JWT pour les clients de l’API
Comme exemple de client d’API, nous utiliserons une application de « système de devis » et créerons un JWT pour ce client. Commençons par définir l’en-tête du JWT :
{
"typ":"JWT",
"alg":"HS256",
"kid":"0001"
}Le champ « typ » définit le type comme étant un jeton Web JSON, le champ « alg » indique que le JWT est signé avec l’algorithme HMAC SHA256, et le champ « kid » indique que le JWT est signé avec la clé Web JSON portant ce numéro de série.
Ensuite, nous définissons la charge utile du JWT :
{
"name":"Quotation System",
"sub":"quotes",
"iss":"My API Gateway"
}Le champ « sub » (sujet) est notre identifiant unique pour la valeur complète du champ « name ». Le champ « iss » indique l’émetteur du JWT, ce qui est utile si votre passerelle API accepte également des JWT provenant d’émetteurs tiers ou d’un système centralisé de gestion des identités.
Maintenant que nous disposons de tout ce dont nous avons besoin pour créer le JWT, suivons les étapes ci-dessous afin de l’encoder et de le signer correctement. Les commandes et les valeurs encodées sont présentées sur plusieurs lignes uniquement pour en faciliter la lecture ; en réalité, chacune est saisie ou affichée sur une seule ligne.
- Aplatissez séparément l’en-tête et la charge utile, puis encodez-les en Base64URL.
$ echo -n '{"typ":"JWT","alg":"HS256","kid":"0001"}' | base64 | tr '+/' '-_' | tr -d '='eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEifQ
$ echo -n '{"name":"Quotation System","sub":"quotes","iss":"My API Gateway"}' | base64 | tr '+/' '-_' | tr -d '='
eyJuYW1lIjoiUXVvdGF0aW9uIFN5c3RlbSIsInN1YiI6InF1b3RlcyIsImlzcyI6Ik
15IEFQSSBHYXRld2F5In0- Concaténez l’en-tête et la charge utile encodés en les séparant par un point (.), puis affectez le résultat à la variable
HEADER_PAYLOAD.
$ HEADER_PAYLOAD=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEifQ.eyJuYW1lIjoiUXVvdGF0aW9uIFN5c3RlbSIsInN1YiI6InF1b3RlcyIsIm lzcyI6Ik15IEFQSSBHYXRld2F5In0- Signez l’en-tête et la charge utile avec notre clé symétrique, puis encodez la signature en Base64URL.
$ echo -n $HEADER_PAYLOAD | openssl dgst -binary -sha256 -hmac fantasticjwt | base64 | tr '+/' '-_' | tr -d '='ggVOHYnVFB8GVPE-VOIo3jD71gTkLffAY0hQOGXPL2I- Ajoutez la signature encodée à l’en-tête et à la charge utile.
$ echo $HEADER_PAYLOAD.ggVOHYnVFB8GVPE-VOIo3jD71gTkLffAY0hQOGXPL2I > quotes.jwt- Effectuez un test en envoyant une requête authentifiée à la passerelle API (dans cet exemple, la passerelle s’exécute sur localhost).
$ curl -H "Authorization: Bearer `cat quotes.jwt`" http://localhost/products/widget1La commande curl de l’étape 5 envoie le JWT à NGINX Plus sous la forme d’un jeton Bearer, ce que NGINX Plus attend par défaut. NGINX Plus peut également récupérer le JWT à partir d’un cookie ou d’un paramètre de chaîne de requête. Pour le configurer, ajoutez le paramètre token= à la directive auth_jwt. Par exemple, avec la configuration suivante, NGINX Plus peut valider le JWT envoyé avec cette commande curl :
$ curl http://localhost/products/widget1?apijwt=`cat quotes.jwt`server {
listen 80;
location /products/ {
auth_jwt "Products API" token=$arg_apijwt;
auth_jwt_key_file conf/api_secret.jwk;
proxy_pass http://api_server;
}
}Une fois NGINX Plus configuré et le JWT généré et vérifié comme indiqué ci-dessus, vous pouvez envoyer le JWT au développeur du client API et convenir du mécanisme qui sera utilisé pour transmettre le JWT avec chaque requête API.
Exploiter les revendications JWT pour la journalisation et la limitation du débit
L’un des principaux avantages des JWT en tant qu’identifiants d’authentification est qu’ils véhiculent des « revendications », qui représentent les entités associées au JWT et à sa charge utile (par exemple, son émetteur, l’utilisateur auquel il a été délivré et le destinataire prévu). Après avoir validé le JWT, NGINX Plus peut accéder sous forme de variables à tous les champs présents dans l’en-tête et la charge utile. Pour y accéder, il suffit d’ajouter le préfixe $jwt_header_ ou $jwt_claim_ au champ souhaité (par exemple, $jwt_claim_sub pour la revendication sub). Cela signifie que nous pouvons très facilement transmettre les informations contenues dans le JWT au point de terminaison de l’API, sans avoir à implémenter le traitement des JWT dans l’API elle-même.
Cet exemple de configuration illustre certaines des fonctionnalités avancées.
log_format jwt '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'$jwt_header_alg $jwt_claim_sub';
limit_req_zone $jwt_claim_sub zone=10rps_per_client:1m rate=10r/s;
server {
listen 80;
location /products/ {
auth_jwt "Products API";
auth_jwt_key_file conf/api_secret.jwk;
limit_req zone=10rps_per_client;
proxy_pass http://api_server;
proxy_set_header API-Client $jwt_claim_sub;
access_log /var/log/nginx/access_jwt.log jwt;
}
}La directive « log_format » définit un nouveau format appelé « jwt », qui enrichit le format de journalisation courant de deux champs supplémentaires : $jwt_header_alg et $jwt_claim_sub. Dans le bloc « location », nous utilisons la directive « access_log » pour consigner les valeurs obtenues à partir du JWT validé.
Dans cet exemple, nous utilisons également des variables basées sur les revendications afin de limiter le débit de l’API par client API plutôt que par adresse IP. Cette approche est particulièrement utile lorsque plusieurs clients API sont intégrés à un même portail et ne peuvent pas être différenciés par leur adresse IP. La directive « limit_req_zone » utilise la revendication « sub » du JWT comme clé pour calculer les limites de débit, qui sont ensuite appliquées au bloc « location » en y incluant la directive « limit_req ».
Enfin, nous transmettons le sujet du JWT sous la forme d’un nouvel en-tête HTTP lorsque la requête est relayée vers le point de terminaison de l’API. La directive proxy_set_header ajoute un en-tête HTTP nommé API‑Client, que le point de terminaison de l’API peut facilement exploiter. Celui-ci n’a donc pas besoin d’implémenter de logique de traitement des JWT. Cet avantage devient d’autant plus important que le nombre de points de terminaison de l’API augmente.
Révocation des JWT
Il peut parfois être nécessaire de révoquer ou de réémettre le JWT d’un client d’API. En combinant un simple bloc map avec la directive auth_jwt_require, nous pouvons refuser l’accès à un client d’API en marquant son JWT comme non valide jusqu’à ce que la date d’expiration du JWT (indiquée dans la revendication exp) soit atteinte. L’entrée map correspondant à ce JWT peut alors être supprimée en toute sécurité.
Dans cet exemple, nous définissons la variable $jwt_status sur 0 ou 1 en fonction de la valeur de la revendication sub dans le jeton (telle qu’elle est enregistrée dans la variable $jwt_claim_sub). Nous utilisons ensuite la directive auth_jwt_require dans le bloc location pour valider (ou rejeter) également le jeton. Pour que celui-ci soit valide, la variable $jwt_status ne doit être ni vide ni égale à 0 (zéro).
map $jwt_claim_sub $jwt_status { "quotes" 0; "test" 0; default 1;
}
server {
listen 80;
location /products/ {
auth_jwt "Products API";
auth_jwt_key_file conf/api_secret.jwk;
auth_jwt_require $jwt_status;
proxy_pass http://api_server;
}
}Résumé
Les jetons Web JSON sont particulièrement adaptés pour fournir un accès authentifié aux API. Pour les développeurs de clients d’API, ils sont aussi faciles à utiliser que les clés d’API traditionnelles et fournissent à la passerelle d’API des informations d’identité qui nécessiteraient autrement une recherche dans une base de données. NGINX Plus prend en charge l’authentification JWT et propose des solutions de configuration avancées fondées sur les informations contenues dans le JWT lui-même. Associé à d’autres fonctionnalités de passerelle d’API, NGINX Plus vous permet de fournir des services basés sur des API avec rapidité, fiabilité, évolutivité et sécurité.
Pour essayer vous-même JWT avec NGINX Plus, commencez votre essai gratuit de 30 jours dès aujourd’hui ou contactez-nous pour discuter de vos cas d’utilisation.
À propos de l’auteur

Articles de blog associés

Tendances actuelles des technologies cloud natives, de l’ingénierie de plateforme et de l’IA
Découvrez les principaux enseignements tirés des réponses à l’enquête annuelle F5 NGINX sur les dernières tendances en matière de technologies cloud natives, de sécurité, d’ingénierie de plateforme et d’IA.
Quels contrôleurs Ingress NGINX sont affectés par les vulnérabilités CVE-2022-4886, CVE-2023-5043 et CVE-2023-5044 ?
Lorsque de nouvelles CVE sont signalées, il est facile de ne plus savoir si elles concernent un outil de contrôleur Ingress NGINX particulier, car il existe plusieurs projets. Cet article présente les CVE et explique comment distinguer les différents projets de contrôleurs Ingress afin de dissiper toute confusion.
Votre API est-elle en temps réel ? Testez sa latence avec l’outil rtapi de NGINX
Votre API répond-elle aux requêtes en moins de 30 ms ? Si ce n’est pas le cas, il ne s’agit pas d’une API en temps réel offrant la faible latence exigée par la grande majorité des organisations. Mesurez la latence de votre API avec l’outil rtapi de NGINX et découvrez comment NGINX peut l’aider à offrir une réactivité en temps réel.

Un testeur d’expressions régulières pour NGINX et NGINX Plus
Le testeur d’expressions régulières (regex) pour NGINX et NGINX Plus vous évite de tâtonner en vous indiquant si une expression régulière utilisée dans un bloc location ou map correspond aux valeurs comme prévu. Il génère la configuration appropriée et affiche les valeurs des groupes de capture.
Caches partagés avec les clusters de cache NGINX Plus, partie 1
Optimisez la capacité de votre cache web en le répartissant entre plusieurs serveurs de cache web NGINX ou NGINX Plus. Découvrez comment procéder dans cet article.
Introduction aux microservices
Les microservices suscitent actuellement beaucoup d’intérêt. Cet article de blog est le premier d’une série de sept consacrée à la conception, au développement et au déploiement de microservices.