OAuth 2.0 Client Credential Flow with Certificate-based Authentication on Microsoft Identity Platform

The Microsoft identity platform allows an application to use its own credentials for authentication anywhere a client secret could be used, for example, in the OAuth 2.0 client credentials grant flow. Assuming we have an application, which needs to authenticate against Azure Active Directory (Azure AD) to obtain an access token for calling downstream API protected by Azure API Management. When registering client application in Azure AD, we could either setup a client secret, or a certificate representing client secret for to be used in combination with client id as credentials.
Why using a certificate is better than a client secret?
A client secret is shared as a plain text. In an access token request, a client transmits the shared secret without any masking. Anyone with knowledge of the client id and the shared secret can impersonate the client.
On the other hand, when using a certificate, a client does not transmit the certificate. Instead, the client uses certificate’s private key to sign the request. Azure AD validates the signature of received request using the public key of the certificate. Azure AD confirms the request was signed by a client which possesses the certificate if the signature validation is successful.
This is how client credentials grant flow can be represented on a sequence diagram.

- Azure AD Administrator registers a client application in Azure AD.
- Client application registration in Azure AD is completed, Application (client) ID and the Directory (tenant) ID values generated to be used later to acquire the Access Token from Azure AD.
- Client application retrieves Access Token from cache if it was previously acquired and cached. This method takes care of verifying the application token cache before sending a request to the Microsoft Identity platform to acquire a new access token.
- If previously used Access Token not found, client application calls Azure AD Token endpoint with certain parameters like: client_id, scope, client_assertion and client_assertion_type, to acquire an Access Token. The Microsoft identity platform token issuance endpoint validates client’s application credentials along with signed token and issues the access token for calling resource API. Note, access token response does not include refresh token.
- Client saves received token in cache.
- Client retrieves Access Token from cache.
- Client provides Access Token in the request’s authorization header sent to resource API, protected by API Management.
- API Management validates received token using JWT Validation policy.
- If the Access Token is valid, the request is passed to the resource API
- Optionally, resource API can perform additional token validations (e.g. validate the access token scope, etc).
- Resource API sends requested data back to the client.
Let’s go through the steps required for configuring and enabling OAuth 2.0 client credential grant flow for a sample application using a certificate as a credential.
- First create client’s SSL/TLS certificate
For our sample application we will be using a self-signed certificate. To generate a self-signed certificate on Linux or Windows (using WSL — Windows Subsystem for Linux), we can use the following OpenSSL commands:
- Generate a private key
openssl genrsa -out clientapp.pem 2048
- Create a certificate signing request
openssl req -new -key clientapp.pem -out aadappcert.csr
- Generate a public certificate
openssl x509 -req -days 365 -in clientapp.csr -signkey clientapp.pem -out clientapp.crt
2. Register a sample application in Azure AD to represent a client application
For client application to be able to acquire Azure AD Access Token, it needs to have a corresponding Azure AD App Registration. In this section, we’ll configure the App Registration in Azure AD.
Sign into your Azure AD portal, navigate to App Registrations and click on the + New Registration button. Give the app a meaningful name and press Register.

Once we’ve registered the client application, we will receive Application (client) ID and the Directory (tenant) ID values, which we will be using later.

3. Upload the public certificate to Azure AD App Registration
We also need to associate a client secret with our client application registration. As a client secret let’s use the public key of our self-signed certificate created in step 1.
Please note that for client credential grant flow the certificate does not need to meet SSL validation criteria when it comes to subject, issuer, etc. We simply need to upload it to the App Registration. Let’s upload the .CER file created in step 1 which represents the public key.
Navigate to the Certificates and Secrets tab and select Certificates tab. Click on Upload Certificate option. Next you will need to upload that .cer file in the App registrations, like shown below.

This is how uploaded certificate looks like:

4. Configure Accepted Token Version
Azure AD OAuth 2.0 token endpoint supports 2 versions of tokens - v1.0 and v2.0. accessTokenAcceptedVersion value in the application manifest file specifies the access token version expected by the resource. This parameter changes the version and format of the JWT produced independent of the endpoint or client used to request the access token. Possible values for accesstokenAcceptedVersion are 1, 2, or null. If the value is null, this parameter defaults to 1, which corresponds to the v1.0 endpoint. For the purpose of our demo, we will use v2.0 token.
Below are the steps to specify the value of the token:
1. In App Registration under Azure AD select your app and then select Manifest.
2. Find the property accessTokenAcceptedVersion in the manifest.
3. Changed the token version to 2, select Save.

5. Define Resource Scope
OAuth 2.0 scopes provide a way to manage permissions to protected resources. When an access token is requested, the client application needs to specify the desired permissions in the scope parameter of the request. In App Registrations under Azure AD select your resource applications. Because your resource application is exposing APIs, select Expose an API option from the left side menu.
Then click on Add a scope. When you click on Add a scope, a new dialog opens on right and it shows Application ID URI which is shown in below snapshot. You can also opt to change it. If you want to change it, the new application ID URI needs to be globally unique. For now, let’s keep the default value and click on Save and Continue button.

In the above dialog box, you can provide the following details:
- Scope name — a name for the scope, e.g. User.Read. The complete scope name should include application id URI.
- Who can consent? — Admins and users
- Admin consent display name
- Admin consent description
- User consent display name
- User consent description
- Set State to Enabled
6. Grant API permissions in Azure AD
On App Registrations screen under Azure Active Directory select your client application. On the left side menu, select API Permissions. In the horizontal menu, click Add a permission.

In the Request API Permissions dialog box, select your resource API (configured above).

Select Delegated permissions and expand User permission options and check User.Read Permission. Click Add permissions.

Now you will see User.Read permission granted to your client application.

7. Authorization and Token endpoints
Now that we have the client application registration and configuration completed, let’s copy the v2 URLs for the Authorization and Token endpoints as per the image below:

8. Configure a JWT validation policy to pre-authorize requests in Azure API Management
The next step is to enable OAuth 2.0 user authorization for your API. This prevents the client application to send requests to your resource API without access token obtained from Azure AD.
Go to APIs menu under the APIM. Select the API you want to protect and go to Design. In the Design view select to edit Inbound Processing Policy, as shown below:

Add Validate JWT policy to your API inbound policy at API level:
At this point we are done with Azure AD configuration.
Let’s see how we can test it!
# Create a signed jwt token (aka Client Assertion)
Access token request with a certificate is slightly different from the classic Access token request with a shared secret flow (using AppId/Secret). In order to prove the identity, client application exchanges a signed client assertion in the form of a signed JWT with the payload containing the required authentication claims (Base64 encoded), with Azure AD to get the access token.
To get an access token using a certificate you must:
- Create a Java Web Token (JWT) header.
- Create a JWT payload.
- Sign the JWT header AND payload with the previously created self-signed certificate. This will create a self-made access token used for requesting an access token.
- Then when the JWT has been created, it is sent to the token endpoint of Azure AD, in order to actually get an access token for our app.
- Create a request body containing:
The parameters for the certificate-based request differ in only one way from the shared secret-based request: the client_secret parameter is replaced by the client_assertion_type and client_assertion parameters.
For our sample application we will be using JSON Web Tokens to generate our client assertion. JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS).
We will be using the following sites:
- Unix Time Stamp — Epoch Converter — to get a future date using the Epoch Unix Timestamp as the JWT will not work otherwise (e.g. 01/11/2029 = 1862842300)
- jwt.io to create a JWT token with payload.
Before proceeding, lets decompose JWT token:
Header
The contents of the Header describe the cryptographic operations to the JWT data. This means that the header contains information about the type of token and the algorithm used to generate the signature (the signing options).
The required properties for the signing options of the JWT are as follows:
Payload
The payload is the central part of the JWT which contains verifiable security statements, such as the identity of the user and the permissions they are allowed. The payload information is also referred to as Claims. Some of these claims have specific meaning, while others are left to be interpreted by the users.
The required claims for a JWT payload are the following:
Signature
JWT tokens are signed so they can’t be altered in transit. When an authorization server issues a token, it signs it using a key.
For our sample application, we are going to use RS256 signing algorithm. RS256 is an RSA Digital Signature Algorithm with SHA-256. SHA-256 is an Asymmetric Key Cryptography algorithm, which uses a pair of keys: a public key and a private key to encrypt and decrypt (we will use our self-signed certificate created in step 1). In this case, the private key is used by the token issuer (our client application), and the public key is used by the application receiving the token to validate it.
Now, let’s use jwt.io to create our client_assertion:

# Use the generated Client Assertion in Postman to get an Access Token.
Use the TenantID and ClientID acquired from client App Registrations in Azure AD. And For client_assertion parameter, use the encrypted token created above.
And now, let’s use Postman to get Access Token from Token endpoint:
Method: POST
URL: https://login.microsoftonline.com/{TenantID}/oauth2/v2.0/token
BODY:
scope=https://{resource-api-app-uri}/.default
&client_id={ClientID}
&client_assertion_type=urn:ietf:params:oauth:client-assertion-&type:jwt-bearer
&client_assertion={assertion we received from jwt.io}
&grant_type=client_credentials
Here is the Postman screen shot:

And in the request’s response we should get our Access Token:

# Now, call the resource API endpoint
Now we need to provide Access Token in the Authorization header to call our resource APIs:


As we can see, we received a successful response status (200) and body containing json payload from the resource API. If we had not provided a valid Authorization header, we’d received “Unauthorized” response code (401) with “Unauthorized. Access token is missing or invalid.” response body.
Now, since we validated our OAuth 2.0 Client Credential Flow with Certificate-based Authentication on Microsoft Identity Platform works as expected, you can proceed using one of many Authentication libraries available for the programming language of your preference. For example, here you can see MSAL methods code snippets for C#.
If you prefer codding in Python, you can find a sample code here.
Happy coding!!! ㋡