On this post, I share a way to get a JWT token on Entra using a client SSL certificate instead of a secret stored at the Entra level.
Entra (formerly Azure AD), offers a full range of features for setting up Oauth 2.0 authentication scenarios. You can consult my various publications on this subject:
Of course, it’s possible to combine client/secret JWT tokenization with mutual SSL authentication to the target API (in other words, the backend service). However, it is also possible to dispense with secrecy to obtain the access token, by using the certificate to authenticate to Entra.
You need to declare an App Registration client on Entra. You need to associate your SSL certificate with it on the “Certificates and secrets” tab. The easiest way to do this is via Entra screens in Azure portal. Obviously, only the public key needs to be shared with Entra.
Make sure the certificate is intended for electronic signatures. Once the certificate is associated with the account, it is possible to request a JWT token.
I’ve configured the OAuth 2.0 Client_Credentials flow and added a few authorizations to the Graph API for this client. To obtain the access token that lists my authorizations on the API Graph, it is necessary to consume the endpoint /token with the following body:
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>
The query parameters are :
It’s not necessary (or even possible) to present your client certificate to obtain your token! Instead, you need to generate a JWT assertion (client assertion), and sign it with your certificate. This assertion consists of :
And looks like this:
{ "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: The dot separating each part is required.
The header consists of the following fields:
Once you’ve generated your header and body, you need to sign it with your certificate. Of course, you need to use your certificate’s private key to perform this operation. The resulting signature will guarantee that your assertion conforms to what you generated and has not been altered during transfer to your target API.
Finally, you need to convert your message into a JWT assertion.
To test the call to Entra, I use Postman. Calling the endpoint /token with the items listed above allows me to obtain an access token with a certificate instead of a client secret.
I recommend using one or more libraries that automatically generate assertions from your elements, such as MSAL.Net.