Entra Id : Obtenir un jeton d’accès JWT à l’aide d’un certificat SSL

Oguzhan YIGIT
Publié par Oguzhan YIGIT
Catégorie : Azure / Azure Active Directory / OAuth
30/01/2024

Sur ce post, je partage un moyen d’obtenir un jeton JWT sur Entra en utilisant un certificat SSL client au lieu d’un secret stocké au niveau d’Entra.

Entra (anciennement Azure AD), offre une palette de fonctionnalités complète pour mettre en place des scénarios d’authentification Oauth 2.0. Vous pouvez consulter mes différentes publications à ce sujet :

 

OAuth 2.0 et authentification SSL

Bien entendu, il est possible de combiner l’obtention du jeton JWT à l’aide d’un client/secret, et une authentification SSL mutuelle auprès de l’API ciblée (autrement dit, le service backend). Mais, il est également possible de se passer du secret pour obtenir le jeton d’accès, en utilisant le certificat pour s’authentifier auprès d’Entra.

 

Configuration d’un flux OAuth2 avec certificat

Il est nécessaire de déclarer une App Registration client sur Entra. Il faut lui associer votre certificat SSL sur l’onglet « Certificats et secrets ». Le plus simple est de le réaliser via les écrans d’Entra au niveau du portail Azure. Evidemment, seule la clé publique doit être partagée avec Entra.

upload public key ssl jwt

 

Assurez-vous que le certificat est destiné à la signature électronique. Dès lors que le certificat est associé au compte, il est possible de demander un jeton JWT.

 

Obtention d’un jeton d’accès à l’aide du certificat

J’ai configuré le flux OAuth 2.0 Client_Credentials et j’ai ajouté quelques autorisations  sur l’API Graph pour ce client. Pour obtenir le jeton d’accès qui me liste mes autorisations sur l’API Graph, il est nécessaire de consommer le endpoint /token avec le corps suivant :

grant_type=client_credentials&client_id=<clientId>&scope=<scope>&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=<client_assertion>

Les paramètres de la requête sont :

  • Content-Type (Header) : application/x-www-form-urlencoded
  • grant_type (body) : client_credentials
  • client_id : identifiant du client (l’App Registration)
  • scope : scope ciblé, dans mon cas « https://graph.microsoft.com/.default » pour la GraphAPI
  • client_assertion_type : urn:ietf:params:oauth:client-assertion-type:jwt-bearer
  • client_assertion : assertion JWT (description plus bas)

 

Génération de l’assertion JWT

Il n’est pas nécessaire (et d’ailleurs pas possible) de présenter votre certificat client pour obtenir votre jeton ! Vous devez, au  lieu de cela, générer une assertion JWT (assertion client), et la signer avec votre certificat.  Cette assertion se compose :

  • d’un entête
  • d’un corps
  • d’une signature

Et se présente comme suit :

{
  "alg": "RS256",
  "typ": "JWT",
  "x5t": "hOBcHZi846VCHSJbFAs26Go9VTQ"
}
.
{
  "aud": "https: //login.microsoftonline.com/contoso.onmicrosoft.com/oauth2/v2.0/token",
  "exp": 1484593341,
  "iss": "<clientId>",
  "jti": "22b3bb26-e046-42df-9c96-65dbd72c1c81",
  "nbf": 1484592741,
  "sub": "97e0a5b7-d745-40b6-94fe-5f77d35c6e05"
}
.
"Gh95kHCOEGq5{a lot of characters here}KKJDg"

Note : Le point qui sépare chaque partie est nécessaire.

 

Composition du Header

Le header se compose des champs suivants :

  • alg : en dur, RS256
  • typ : en dur, JWT
  • x5t : empreinte du certificat hashée en base 64

 

Composition de l’entête

  • aud : audience, doit être https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
  • exp : expiration time, date/heure d’expiration du jeton. Doit être supérieure à la date/heure actuelle et a nbf
  • iss : issuer,  émetteur du jeton, dans ce cas précis, c’est le client id
  • jti : un guid, identifiant unique du jeton que nous générons
  • nbf : not before, date à partir de laquelle le jeton est valide
  • sub :subject claim, dans ce cas précis, il faut également utiliser l’id du client de l’App Registration
  • iat : issued at, optionnel et sert à déterminer la date de génération du jeton

 

Signature et génération de l’assertion JWT

Dès lors que vous avez généré votre entête et corps, vous devez le signer avec votre certificat. Bien entendu, il faut utiliser la clé privée de votre certificat pour réaliser cette opération. La signature résultant, garantira que votre assertion est conforme à ce que vous avez générée et n’a pas été altéré durant le transfert vers votre API cible.

Finalement, il est nécessaire de convertir votre message en assertion JWT.

 

Tester l’obtention du jeton JWT

Pour tester l’appel à Entra, j’utilise Postman. L’appel au endpoint /token avec les éléments énumérés précédemment me permettent d’obtenir un jeton d’accès avec un certificat au lieu d’un secret client.

test postman jwt access token certificate entra id

 

Utiliser des librairies

Je vous conseille d’utiliser une ou plusieurs librairies qui génère automatiquement l’assertion à partir de vos éléments, par exemple MSAL.Net.