Microsoft identity platform application authentication certificate credentials

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 and the on-behalf-of (OBO) flow.

One form of credential that an application can use for authentication is a JSON Web Token (JWT) assertion signed with a certificate that the application owns. This is described in the OpenID Connect specification for the private_key_jwt client authentication option.

If you're interested in using a JWT issued by another identity provider as a credential for your application, please see workload identity federation for how to set up a federation policy.

Assertion format

To compute the assertion, you can use one of the many JWT libraries in the language of your choice - MSAL supports this using .WithCertificate(). The information is carried by the token in its Header, Claims, and Signature.

Parameter Remark
alg Should be PS256
typ Should be JWT
x5t#s256 Base64url-encoded SHA-256 thumbprint of the X.509 certificate's DER encoding.

Claims (payload)

Claim type Value Description
aud https://login.partner.microsoftonline.cn/{tenantId}/oauth2/v2.0/token The "aud" (audience) claim identifies the recipients that the JWT is intended for (here Microsoft Entra ID) See RFC 7519, Section 4.1.3. In this case, that recipient is the login server (login.partner.microsoftonline.cn).
exp 1601519414 The "exp" (expiration time) claim identifies the expiration time on or after which the JWT must not be accepted for processing. See RFC 7519, Section 4.1.4. This allows the assertion to be used until then, so keep it short - 5-10 minutes after nbf at most. Microsoft Entra ID doesn't place restrictions on the exp time currently.
iss {ClientID} The "iss" (issuer) claim identifies the principal that issued the JWT, in this case your client application. Use the GUID application ID.
jti (a Guid) The "jti" (JWT ID) claim provides a unique identifier for the JWT. The identifier value must be assigned in a manner that ensures that there's a negligible probability that the same value will be accidentally assigned to a different data object; if the application uses multiple issuers, collisions MUST be prevented among values produced by different issuers as well. The "jti" value is a case-sensitive string. RFC 7519, Section 4.1.7
nbf 1601519114 The "nbf" (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing. RFC 7519, Section 4.1.5. Using the current time is appropriate.
sub {ClientID} The "sub" (subject) claim identifies the subject of the JWT, in this case also your application. Use the same value as iss.
iat 1601519114 The "iat" (issued at) claim identifies the time at which the JWT was issued. This claim can be used to determine the age of the JWT. RFC 7519, Section 4.1.5.

Signature

The signature is computed by applying the certificate as described in the JSON Web Token RFC7519 specification. Use PSS padding.

Example of a decoded JWT assertion

{
  "alg": "PS256",
  "typ": "JWT",
  "x5t#sha256": "A1bC2dE3fH4iJ5kL6mN7oP8qR9sT0u"
}
.
{
  "aud": "https: //login.partner.microsoftonline.cn/contoso.partner.onmschina.cn/oauth2/v2.0/token",
  "exp": 1484593341,
  "iss": "aaaabbbb-0000-cccc-1111-dddd2222eeee",
  "jti": "00aa00aa-bb11-cc22-dd33-44ee44ee44ee",
  "nbf": 1484592741,
  "sub": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb"
}
.
"A1bC2dE3fH4iJ5kL6mN7oP8qR9sT0u..."

Example of an encoded JWT assertion

The following string is an example of encoded assertion. If you look carefully, you notice three sections separated by dots (.):

  • The first section encodes the header
  • The second section encodes the claims (payload)
  • The last section is the signature computed with the certificates from the content of the first two sections
"eyJhbGciOiJSUzI1NiIsIng1dCI6Imd4OHRHeXN5amNScUtqRlBuZDdSRnd2d1pJMCJ9.eyJhdWQiOiJodHRwczpcL1wvbG9naW4ubWljcm9zb2Z0b25saW5lLmNvbVwvam1wcmlldXJob3RtYWlsLm9ubWljcm9zb2Z0LmNvbVwvb2F1dGgyXC90b2tlbiIsImV4cCI6MTQ4NDU5MzM0MSwiaXNzIjoiOTdlMGE1YjctZDc0NS00MGI2LTk0ZmUtNWY3N2QzNWM2ZTA1IiwianRpIjoiMjJiM2JiMjYtZTA0Ni00MmRmLTljOTYtNjVkYmQ3MmMxYzgxIiwibmJmIjoxNDg0NTkyNzQxLCJzdWIiOiI5N2UwYTViNy1kNzQ1LTQwYjYtOTRmZS01Zjc3ZDM1YzZlMDUifQ.
Gh95kHCOEGq5E_ArMBbDXhwKR577scxYaoJ1P{a lot of characters here}KKJDEg"

Register your certificate with Microsoft identity platform

You can associate the certificate credential with the client application in the Microsoft identity platform through the Microsoft Entra admin center using any of the following methods:

Uploading the certificate file

In the App registrations tab for the client application:

  1. Select Certificates & secrets > Certificates.
  2. Select on Upload certificate and select the certificate file to upload.
  3. Select Add. Once the certificate is uploaded, the thumbprint, start date, and expiration values are displayed.

Updating the application manifest

After acquiring a certificate, compute these values:

  • $base64Thumbprint - Base64-encoded value of the certificate hash
  • $base64Value - Base64-encoded value of the certificate raw data

Provide a GUID to identify the key in the application manifest ($keyId).

In the Azure app registration for the client application:

  1. Select Manifest to open the application manifest.

  2. Replace the keyCredentials property with your new certificate information using the following schema.

    "keyCredentials": [
        {
            "customKeyIdentifier": "$base64Thumbprint",
            "keyId": "$keyid",
            "type": "AsymmetricX509Cert",
            "usage": "Verify",
            "value":  "$base64Value"
        }
    ]
    
  3. Save the edits to the application manifest and then upload the manifest to Microsoft identity platform.

    The keyCredentials property is multi-valued, so you may upload multiple certificates for richer key management.

Using a client assertion

Client assertions can be used anywhere a client secret would be used. For example, in the authorization code flow, you can pass in a client_secret to prove that the request is coming from your app. You can replace this with client_assertion and client_assertion_type parameters.

Parameter Value Description
client_assertion_type urn:ietf:params:oauth:client-assertion-type:jwt-bearer This is a fixed value, indicating that you're using a certificate credential.
client_assertion JWT This is the JWT created above.

Next steps

The MSAL.NET library handles this scenario in a single line of code.

The .NET daemon console application using Microsoft identity platform code sample on GitHub shows how an application uses its own credentials for authentication. It also shows how you can create a self-signed certificate using the New-SelfSignedCertificate PowerShell cmdlet. You can also use the app creation scripts in the sample repo to create certificates, compute the thumbprint, and so on.