Français
  • oauth
  • jwt
  • api
  • sécurité
  • authentification
  • autorisation
  • machine-to-machine

Sécurisez vos ressources d'API pour la communication entre machines

Découvrez comment exploiter OAuth 2.0 et JWT pour sécuriser vos ressources d'API pour la communication entre machines.

Gao
Gao
Founder

Lors de la création d'un projet impliquant plusieurs services, la sécurité des ressources de l'API est une préoccupation essentielle. Dans cet article, je vous montrerai comment tirer parti d'OAuth 2.0 et JWT pour sécuriser la communication entre services (machine à machine), et comment appliquer le contrôle d'accès basé sur les rôles (RBAC) pour suivre le principe de privilège minimum.

Commencer

Pour suivre, je suppose que vous avez les prérequis suivants :

  • Un compte Logto Cloud, ou une instance Logto auto-hébergée
  • Au moins deux services qui doivent communiquer l'un avec l'autre

À des fins de démonstration, supposons que nous ayons les services suivants :

  • Un service de panier d'achat qui fournit des APIs pour gérer les paniers d'achat
    • Point de terminaison : https://cart.example.com/api
  • Un service de paiement qui fournit des APIs pour traiter les paiements
    • Point de terminaison : https://payment.example.com/api

Flux d'authentification

Maintenant, notre service de panier doit appeler le service de paiement pour traiter les paiements. Le flux d'authentification est le suivant :

Quelques concepts clés dans le diagramme ci-dessus :

  • JWT (RFC 7519) : JSON Web Token. Consultez notre article précédent pour une introduction à JWT.
  • JWK (RFC 7517) : JSON Web Key qui est utilisé pour vérifier la signature d'un JWT. Un ensemble de JWK est un ensemble de JWK.
  • "client_credentials" grant (RFC 6749) : Un type de concession dans OAuth 2.0. Il utilise les informations d'identification du client pour obtenir un token d'accès. Nous démontrerons les détails dans les sections à venir.

Chaque participant dans le diagramme ci-dessus a un rôle à jouer dans le flux d'authentification :

  • Service de panier : Le client qui doit appeler le service de paiement. Bien que ce soit un service, c'est toujours un client dans le contexte OAuth 2.0, et nous appelons ces clients des "applications machine à machine" dans Logto.
  • Logto : Le serveur d'autorisation OAuth 2.0 qui délivre les tokens d'accès.
  • Service de paiement : La ressource d'API qui fournit des APIs pour traiter les paiements.

Passons en revue le flux d'authentification étape par étape.

Configuration initiale

Pour effectuer le flux d'authentification, nous devons créer une application machine à machine (service de panier) et une ressource d'API (service de paiement) dans Logto.

Créer une ressource d'API

Étant donné que notre service de panier doit être conscient de l'API du service de paiement lors de l'authentification, nous devons d'abord créer une ressource d'API. Allez dans Logto Console, cliquez sur API resources dans la barre latérale gauche et cliquez sur Create API resource. Dans la boîte de dialogue ouverte, nous offrons quelques tutoriels pour vous aider à démarrer. Vous pouvez également cliquer sur Continue without tutorial pour le sauter.

Entrez le nom et l'identifiant de l'API, par exemple, Service de paiement et https://payment.example.com/api, puis cliquez sur Create API resource.

Après avoir créé la ressource d'API, vous serez redirigé vers la page de détails. Nous pouvons la laisser telle quelle pour le moment.

Créer une application machine à machine

Cliquez sur Applications dans la barre latérale gauche et cliquez sur Create application. Dans la boîte de dialogue ouverte, trouvez la carte Machine-to-machine et cliquez sur Start building.

Entrez le nom de l'application, par exemple, Service de panier, et cliquez sur Create application. Un guide interactif vous sera présenté pour vous aider à configurer l'application. Vous pouvez suivre le guide pour comprendre l'utilisation de base, ou cliquer sur Finish and done pour le sauter.

Demander un token d'accès

Étant donné que les applications machine à machine sont supposées être sécurisées (par exemple, elles sont déployées dans un réseau privé), nous pouvons utiliser l'autorisation "client_credentials" d'OAuth 2.0 pour obtenir un token d'accès. Elle utilise l'authentification de base pour authentifier le client :

  • L'URL de la requête est le point de terminaison du token de votre instance Logto. Vous pouvez la trouver et la copier dans l'onglet Advanced settings de la page des détails de l'application machine à machine.
  • La méthode de la requête est POST.
  • L'en-tête Content-Type de la requête est application/x-www-form-urlencoded.
  • Pour l'en-tête Authorization, la valeur est Basic <base64(app_id:app_secret)>, où app_id et app_secret sont l'ID et le secret de l'application machine à machine respectivement. Vous pouvez les trouver sur la page des détails de l'application.
  • Le corps de la requête doit spécifier le type de concession et l'identifiant de l'API. Par exemple, grant_type=client_credentials&resource=https://payment.example.com/api.
    • grant_type=client_credentials : La valeur constante pour la concession "client_credentials".
    • resource=https://payment.example.com/api : L'identifiant de l'API de la ressource d'API que le client souhaite accéder.
    • Si l'application doit être autorisée avec des portées (permissions), vous pouvez également spécifier les portées dans le corps de la requête. Par exemple, scope=read:payment write:payment. Nous couvrirons les portées plus tard.

Voici un exemple de la requête utilisant curl :

Un corps de réponse réussi serait comme :

Envoyer une demande avec l'en-tête d'autorisation

Nous avons maintenant le token d'accès, et nous pouvons l'ajouter à l'en-tête Authorization de la requête à la ressource d'API. Par exemple, si nous voulons appeler l'API POST /payments du service de paiement, nous pouvons envoyer la demande suivante :

Valider JWT

Vous remarquerez peut-être que le service de paiement doit valider le JWT en utilisant le jeu de JWK, et peut avoir un cache de jeu de JWK local pour éviter de récupérer le jeu de JWK de Logto à chaque fois. Heureusement, en raison de la popularité de JWT, il existe de nombreuses bibliothèques qui peuvent vous aider à atteindre cet objectif avec quelques lignes de code.

Ces bibliothèques sont généralement appelées "jose" (JavaScript Object Signing and Encryption) ou "jsonwebtoken". Par exemple, dans Node.js, nous pouvons utiliser jose pour valider le JWT :

Si la validation réussit, la variable payload sera la charge utile JWT décodée. Sinon, une erreur sera générée.

Appliquer le contrôle d'accès basé sur les rôles

Nous avons maintenant réussi à sécuriser la communication entre le service de panier et le service de paiement. Cependant, le flux d'authentification ne garantit que le client est le véritable service de panier, mais ne garantit pas que le service de panier a quelconque permission pour effectuer des actions sur le service de paiement.

Disons que nous voulons permettre au service de panier de créer des paiements, mais pas de lire les paiements.

Définir les permissions

Dans Logto, les "portées" et les "permissions" sont interchangeables. Allez à la page des détails de la ressource d'API du service de paiement, et naviguez vers l'onglet Permissions. Il devrait être vide maintenant. Cliquez sur Create permission, entrez read:payment comme nom de la permission, et entrez Lire les paiements comme description de la permission. Puis cliquez sur Create permission.

Répétez les étapes ci-dessus pour créer une autre permission avec le nom write:payment et la description Créer des paiements.

Créer un rôle machine à machine

Un rôle est un groupe de permissions. Dans Logto, les applications machine à machine peuvent se voir attribuer des rôles pour accorder des permissions. Cliquez sur "Roles" dans la barre latérale gauche, et cliquez sur Create role.

  1. Entrez checkout comme nom du rôle, et entrez Service de paiement comme description du rôle.
  2. Cliquez sur Show more options. Choisissez "Machine-to-machine app role" comme type de rôle.
  3. Dans la section "Assigned permissions", cliquez sur l'icône de flèche sur la gauche du nom de la ressource d'API (Service de paiement), et sélectionnez la permission write:payment.
    Créer rôle
  4. Cliquez sur Create role.
  5. Étant donné que nous avons déjà une application machine à machine (Service de panier), nous pouvons directement attribuer le rôle à cela dans l'étape suivante. Cochez la case à gauche du nom de l'application (Service de panier), et cliquez sur Assign applications.
Attribuer rôle à l'application

Demander un token d'accès avec des portées

En plus des paramètres du corps de la requête que nous avons mentionnés dans Demander un token d'accès, nous pouvons également spécifier les portées dans le corps de la requête. Par exemple, si nous voulons demander la permission write:payment, nous pouvons envoyer la requête suivante :

Pour demander plusieurs portées, vous pouvez les séparer par des espaces. Par exemple, scope=write:payment read:payment.

Valider les portées

Si une action nécessite la permission write:payment dans le service de paiement, nous pouvons valider les portées en vérifiant que la revendication scope de la charge utile JWT :

Conclusion

Si vous souhaitez protéger l'accès au service de panier, vous pouvez également appliquer le même flux d'authentification. Cette fois, le service de panier est la ressource d'API, et le client est un autre service qui doit accéder.

Avec Logto, vos ressources d'API sont sécurisées avec OAuth 2.0 et JWT, et vous pouvez suivre le principe de privilège minimum en appliquant le contrôle d'accès basé sur les rôles. De plus, vous pouvez également utiliser Logto pour gérer vos utilisateurs et leurs permissions, et même vous intégrer à des fournisseurs d'identité tiers.