The Microsoft identity platform supports three types of credentials to authenticate apps and service principals: passwords (app secrets), certificates, and federated identity credentials. If you can't use federated identity credentials for your app, we strongly recommend that you use certificates instead of secrets.
This article provides guidance for using Microsoft Graph and PowerShell scripts to update certificate credentials programmatically for an app registration.
Prerequisites
To complete this tutorial, you need the following resources and privileges:
An active Microsoft Entra tenant.
An API client such as Graph Explorer. Sign in as a user who is allowed to create and manage applications in the tenant. The Application Developer (of an app they own) and Application Administrator role are the least privileged roles that can perform this operation.
The use of certificates is highly recommended over secrets; however, we don't recommend using self-signed certificates. They can reduce the security bar of your application due to various factors like use of an outdated hash and cipher suites or lack of validation. We recommend procuring certificates from a well known trusted certificate authority.
Step 1: Read the certificate details
To add a certificate programmatically using Microsoft Graph, you need the certificate's key. You can optionally add the certificate's thumbprint.
[Optional] Get the certificate thumbprint
It's optional to add the certificate thumbprint to the request payload. If you want to add the thumbprint, you can run the following PowerShell request to read the certificate's thumbprint. This request assumes that you generated and exported the certificate to your local drive.
Request
## Replace the file path with the source of your certificate and output path with the location where you want to save the thumprint details
Get-PfxCertificate -Filepath "C:\Users\admin\Desktop\20230112.cer" | Out-File -FilePath "C:\Users\admin\Desktop\20230112.cer.thumbprint.txt"
Response
The output in the .txt file can be similar to the following.
To read the certificate's key and save it to a .txt file by using PowerShell, run the following request.
Request
PowerShell < 6:
## Replace the file path with the location of your certificate
[convert]::ToBase64String((Get-Content C:\Users\admin\Desktop\20230112.cer -Encoding byte)) | Out-File -FilePath "C:\Users\admin\Desktop\20230112.key.txt"
PowerShell >= 6:
## Replace the file path with the location of your certificate
[convert]::ToBase64String((Get-Content C:\Users\admin\Desktop\20230112.cer -AsByteStream)) | Out-File -FilePath "C:\Users\admin\Desktop\20230112.key.txt"
Response
The output in the .txt file can be similar to the following.
Note: The key shown here has been shortened for readability.
Step 2: Add the certificate details using Microsoft Graph
Request
The following request adds the certificate details to an app. The settings are as follows:
The startDateTime is the date when or after the certificate was created.
The endDateTime can be a maximum of 1 year from the startDateTime. If unspecified, the system will automatically assign a date 1 year after the startDateTime.
The type and usage must be AsymmetricX509Cert and Verify respectively.
Assign the certificate subject name to the displayName property.
The key is the Base64 encoded value that you generated in the previous step. The thumbprint is included in the encoded key and adding the key also adds the thumbprint.
Note
If your app has an existing valid certificate that you want to continue using for authentication, include both the current and new certificate details in the app's keyCredentials object. Because this a PATCH call, which by protocol replaces the contents of the property with the new values, including only the new certificate will replace the existing certificates with the new one.
The following example adds a new certificate and replaces any existing certificates.
Note: The key shown here has been shortened for readability.
// Code snippets are only available for the latest version. Current version is 5.x
// Dependencies
using Microsoft.Graph.Models;
var requestBody = new Application
{
KeyCredentials = new List<KeyCredential>
{
new KeyCredential
{
EndDateTime = DateTimeOffset.Parse("2024-01-11T15:31:26Z"),
StartDateTime = DateTimeOffset.Parse("2023-01-12T15:31:26Z"),
Type = "AsymmetricX509Cert",
Usage = "Verify",
Key = Convert.FromBase64String("base64MIIDADCCAeigAwIBAgIQP6HEGDdZ65xJTcK4dCBvZzANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAgyMDIzMDExMjAeFw0yMzAxMTIwODExNTZaFw0yNDAxMTIwODMxNTZaMBMxETAPBgNVBAMMCDIwMjMwMTEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAseKf1weEacJ67D6/...laxQPUbuIL+DaXVkKRm1V3GgIpKTBqMzTf4tCpy7rpUZbhcwAFw6h9A=="),
DisplayName = "CN=20230112",
},
},
};
// To initialize your graphClient, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=csharp
var result = await graphClient.Applications["{application-id}"].PatchAsync(requestBody);
// Code snippets are only available for the latest version. Current version is 6.x
GraphServiceClient graphClient = new GraphServiceClient(requestAdapter);
Application application = new Application();
LinkedList<KeyCredential> keyCredentials = new LinkedList<KeyCredential>();
KeyCredential keyCredential = new KeyCredential();
OffsetDateTime endDateTime = OffsetDateTime.parse("2024-01-11T15:31:26Z");
keyCredential.setEndDateTime(endDateTime);
OffsetDateTime startDateTime = OffsetDateTime.parse("2023-01-12T15:31:26Z");
keyCredential.setStartDateTime(startDateTime);
keyCredential.setType("AsymmetricX509Cert");
keyCredential.setUsage("Verify");
byte[] key = Base64.getDecoder().decode("base64MIIDADCCAeigAwIBAgIQP6HEGDdZ65xJTcK4dCBvZzANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAgyMDIzMDExMjAeFw0yMzAxMTIwODExNTZaFw0yNDAxMTIwODMxNTZaMBMxETAPBgNVBAMMCDIwMjMwMTEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAseKf1weEacJ67D6/...laxQPUbuIL+DaXVkKRm1V3GgIpKTBqMzTf4tCpy7rpUZbhcwAFw6h9A==");
keyCredential.setKey(key);
keyCredential.setDisplayName("CN=20230112");
keyCredentials.add(keyCredential);
application.setKeyCredentials(keyCredentials);
Application result = graphClient.applications().byApplicationId("{application-id}").patch(application);
# Code snippets are only available for the latest version. Current version is 1.x
from msgraph import GraphServiceClient
from msgraph.generated.models.application import Application
from msgraph.generated.models.key_credential import KeyCredential
# To initialize your graph_client, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=python
request_body = Application(
key_credentials = [
KeyCredential(
end_date_time = "2024-01-11T15:31:26Z",
start_date_time = "2023-01-12T15:31:26Z",
type = "AsymmetricX509Cert",
usage = "Verify",
key = base64.urlsafe_b64decode("base64MIIDADCCAeigAwIBAgIQP6HEGDdZ65xJTcK4dCBvZzANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAgyMDIzMDExMjAeFw0yMzAxMTIwODExNTZaFw0yNDAxMTIwODMxNTZaMBMxETAPBgNVBAMMCDIwMjMwMTEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAseKf1weEacJ67D6/...laxQPUbuIL+DaXVkKRm1V3GgIpKTBqMzTf4tCpy7rpUZbhcwAFw6h9A=="),
display_name = "CN=20230112",
),
],
)
result = await graph_client.applications.by_application_id('application-id').patch(request_body)
// Code snippets are only available for the latest version. Current version is 5.x
// Dependencies
using Microsoft.Graph.Models;
var requestBody = new Application
{
KeyCredentials = new List<KeyCredential>
{
new KeyCredential
{
EndDateTime = DateTimeOffset.Parse("2024-01-11T15:31:26Z"),
StartDateTime = DateTimeOffset.Parse("2023-01-12T09:31:26Z"),
Type = "AsymmetricX509Cert",
Usage = "Verify",
Key = Convert.FromBase64String("base64MIIDADCCAeigAwIBAgIQejfrj3S974xI//npv7hFHTANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAgyMDIzMDExNDAeFw0yMzAxMTIwOTA4NThaFw0yNDAxMTIwOTI4NThaMBMxETAPBgNVBAMMCDIwMjMwMTE0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt5vEj6j1l5wOVHR4eDGe77HWslaIVJ1NqxrXPm/...+R+U7sboj+kUvmFzXI+Ge73Liu8egL2NzOHHpO43calWgq36a9YW1yhBQR1ioEchu6jmudW3rF6ktmVqQ=="),
DisplayName = "CN=20230114",
},
new KeyCredential
{
CustomKeyIdentifier = Convert.FromBase64String("52ED9B5038A47B9E2E2190715CC238359D4F8F73"),
Type = "AsymmetricX509Cert",
Usage = "Verify",
Key = Convert.FromBase64String("base64MIIDADCCAeigAwIBAgIQfoIvchhpToxKEPI4iMrU1TANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAgyMDIzMDExMzAeFw0yMzAxMTIwODI3NTJaFw0yNDAxMTIwODQ3NTJaMBMxETAPBgNVBAMMCDIwMjMwMTEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+iqg1nMjYmFcFJh/.../S5X6qoEOyJBgtfpSBANWAdA=="),
DisplayName = "CN=20230113",
},
},
};
// To initialize your graphClient, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=csharp
var result = await graphClient.Applications["{application-id}"].PatchAsync(requestBody);
# Code snippets are only available for the latest version. Current version is 1.x
from msgraph import GraphServiceClient
from msgraph.generated.models.application import Application
from msgraph.generated.models.key_credential import KeyCredential
# To initialize your graph_client, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=python
request_body = Application(
key_credentials = [
KeyCredential(
end_date_time = "2024-01-11T15:31:26Z",
start_date_time = "2023-01-12T09:31:26Z",
type = "AsymmetricX509Cert",
usage = "Verify",
key = base64.urlsafe_b64decode("base64MIIDADCCAeigAwIBAgIQejfrj3S974xI//npv7hFHTANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAgyMDIzMDExNDAeFw0yMzAxMTIwOTA4NThaFw0yNDAxMTIwOTI4NThaMBMxETAPBgNVBAMMCDIwMjMwMTE0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt5vEj6j1l5wOVHR4eDGe77HWslaIVJ1NqxrXPm/...+R+U7sboj+kUvmFzXI+Ge73Liu8egL2NzOHHpO43calWgq36a9YW1yhBQR1ioEchu6jmudW3rF6ktmVqQ=="),
display_name = "CN=20230114",
),
KeyCredential(
custom_key_identifier = base64.urlsafe_b64decode("52ED9B5038A47B9E2E2190715CC238359D4F8F73"),
type = "AsymmetricX509Cert",
usage = "Verify",
key = base64.urlsafe_b64decode("base64MIIDADCCAeigAwIBAgIQfoIvchhpToxKEPI4iMrU1TANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAgyMDIzMDExMzAeFw0yMzAxMTIwODI3NTJaFw0yNDAxMTIwODQ3NTJaMBMxETAPBgNVBAMMCDIwMjMwMTEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+iqg1nMjYmFcFJh/.../S5X6qoEOyJBgtfpSBANWAdA=="),
display_name = "CN=20230113",
),
],
)
result = await graph_client.applications.by_application_id('application-id').patch(request_body)
You used Microsoft Graph to update certificate credentials for an app object. This process is a programmatic alternative to using the Microsoft Entra admin center. You can also update certificate credentials for a service principal by following a similar process and calling the https://graph.microsoft.com/v1.0/servicePrincipals/ endpoint.