title | description | author | manager | ms.author | ms.service | ms.topic | ms.date | ms.custom |
---|---|---|---|---|---|---|---|---|
Use client certificate for authentication in your Node.js web app |
Learn how to use client certificate instead of secrets for authentication in your Node.js web app |
kengaderdus |
mwongerapk |
kengaderdus |
identity-platform |
how-to |
03/16/2025 |
[!INCLUDE applies-to-external-only]
Microsoft Entra External ID supports two types of authentication for confidential client applications; password-based authentication (such as client secret) and certificate-based authentication. For a higher level of security, we recommend using a certificate (instead of a client secret) as a credential in your confidential client applications.
In production, you should purchase a certificate signed by a well-known certificate authority, then use Azure Key Vault to manage certificate access and lifetime. However, for testing purposes, you can create a self-signed certificate and configure your apps to authenticate with it.
In this article, you learn to generate a self-signed certificate by using Azure Key Vault on the Azure portal, OpenSSL, or PowerShell. If you have a client secret already, you'll learn how to safely delete it.
When needed, you can also create a self-signed certificate programmatically by using .NET, Node.js, Go, Python or Java client libraries.
-
Visual Studio Code or another code editor.
-
An external tenant. If you don't already have one, sign up for a free trial.
-
OpenSSL or you can easily install OpenSSL in Windows via Chocolatey.
-
Windows PowerShell or Azure subscription.
If you have an existing self-signed certificate in your local computer, you can skip this step, then proceed to Upload certificate to your app registration.
You can use Azure Key Vault to generate a self-signed certificate for your app. By using Azure Key Vault, you enjoy benefits, such as, assigning a partner Certificate Authority (CA) and automating certificate rotation.
If you have an existing self-signed certificate in Azure Key Vault, and you want to use it without downloading it, skip this step, then proceed to Use a self-signed certificate directly from Azure Key Vault. Otherwise, use the following steps to generate your certificate
-
Follow the steps in Set and retrieve a certificate from Azure Key Vault using the Azure portal to create and download your certificate.
-
After you create your certificate, download both the .cer file and the .pfx file such as ciam-client-app-cert.cer and ciam-client-app-cert.pfx. The .cer file contains the public key and is what you upload to your Microsoft Entra admin center.
-
In your terminal, run the following command to extract the private key from the .pfx file. When prompted to type a pass phrase, just press Enter key you if you don't want to set one. Otherwise type a pass phrase of your choice:
openssl pkcs12 -in ciam-client-app-cert.pfx -nocerts -out ciam-client-app-cert.key
The ciam-client-app-cert.key file is what you use in your app.
-
Use the steps in Create a self-signed public certificate to authenticate your application. Make sure you export your public certificate with its private key. For the
certificateName
, use ciam-client-app-cert. -
In your terminal, run the following command to extract the private key from the .pfx file. When prompted to type in your pass phrase, type a pass phrase of your choice:
openssl pkcs12 -in ciam-client-app-cert.pfx -nocerts -out ciam-client-app-cert.key
After you complete these steps, you should have a .cer file and the .key file, such as ciam-client-app-cert.key and ciam-client-app-cert.cer. The .key file is what you use in your app. The .cer file is what you upload to your Microsoft Entra admin center.
In your terminal, run the following command. When prompted to type in your pass phrase, type a pass phrase of your choice:
openssl req -x509 -newkey rsa:2048 -keyout ciam-client-app-cert.key -out ciam-client-app-cert.crt -subj "/CN=ciamclientappcert.com"
After the command finishes execution, you should have a .crt and a .key files, such as ciam-client-app-cert.key and ciam-client-app-cert.crt. The .key file is what you use in your app. The .cer file is what you upload to your Microsoft Entra admin center.
[!INCLUDE active-directory-customers-app-integration-add-user-flow]
[!INCLUDE remove-client-secret]
Once you associate your app registration with the certificate, you need to update your app code to start using the certificate:
-
Locate the file that contains your MSAL configuration object, such as
msalConfig
in authConfig.js, then update it to look similar to the following code. If you have a client secret present, make sure you remove it:require('dotenv').config(); const fs = require('fs'); //// import the fs module for reading the key file const crypto = require('crypto'); const TENANT_SUBDOMAIN = process.env.TENANT_SUBDOMAIN || 'Enter_the_Tenant_Subdomain_Here'; const REDIRECT_URI = process.env.REDIRECT_URI || 'http://localhost:3000/auth/redirect'; const POST_LOGOUT_REDIRECT_URI = process.env.POST_LOGOUT_REDIRECT_URI || 'http://localhost:3000'; const privateKeySource = fs.readFileSync('PATH_TO_YOUR_PRIVATE_KEY_FILE') const privateKeyObject = crypto.createPrivateKey({ key: privateKeySource, passphrase: 'Add_Passphrase_Here', format: 'pem' }); const privateKey = privateKeyObject.export({ format: 'pem', type: 'pkcs8' }); /** * Configuration object to be passed to MSAL instance on creation. * For a full list of MSAL Node configuration parameters, visit: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md */ const msalConfig = { auth: { clientId: process.env.CLIENT_ID || 'Enter_the_Application_Id_Here', // 'Application (client) ID' of app registration in Azure portal - this value is a GUID authority: process.env.AUTHORITY || `https://${TENANT_SUBDOMAIN}.ciamlogin.com/`, clientCertificate: { thumbprint: "YOUR_CERT_THUMBPRINT", // replace with thumbprint obtained during step 2 above privateKey: privateKey } }, //... Rest of code in the msalConfig object }; module.exports = { msalConfig, REDIRECT_URI, POST_LOGOUT_REDIRECT_URI, TENANT_SUBDOMAIN };
In your code, replace the placeholders:
-
Add_Passphrase_Here
with the pass phrase you used to encrypt your private key. -
YOUR_CERT_THUMBPRINT
with the Thumbprint value you recorded earlier. -
PATH_TO_YOUR_PRIVATE_KEY_FILE
with the file path to your private key file. -
Enter_the_Application_Id_Here
with the Application (client) ID of the app you registered earlier. -
Enter_the_Tenant_Subdomain_Here
and replace it with the Directory (tenant) subdomain. For example, if your tenant primary domain iscontoso.onmicrosoft.com
, usecontoso
. If you don't have your tenant name, learn how to read your tenant details.
We encrypted the key (we recommend that you do so), so we have to decrypt it before we pass it to MSAL configuration object.
//... const privateKeyObject = crypto.createPrivateKey({ key: privateKeySource, passphrase: 'Add_Passphrase_Here', format: 'pem' }); const privateKey = privateKeyObject.export({ format: 'pem', type: 'pkcs8' }); //...
-
-
Use the steps in Run and test the web app to test your app.
You can use your existing certificate directly from Azure Key Vault:
-
Locate the file that contains your MSAL configuration object, such as
msalConfig
in authConfig.js, then remove theclientSecret
property:const msalConfig = { auth: { clientId: process.env.CLIENT_ID || 'Enter_the_Application_Id_Here', // 'Application (client) ID' of app registration in Azure portal - this value is a GUID authority: process.env.AUTHORITY || `https://${TENANT_SUBDOMAIN}.ciamlogin.com/`, }, //... };
-
Install Azure CLI, then on your console, type the following command to sign-in:
az login --tenant YOUR_TENANT_ID
Replace the placeholder
YOUR_TENANT_ID
with the Directory (tenant) ID you copied earlier. -
On your console, type the following command to install the required packages:
npm install --save @azure/identity @azure/keyvault-certificates @azure/keyvault-secrets
-
In your client app, use the following code to generate
thumbprint
andprivateKey
;const identity = require("@azure/identity"); const keyvaultCert = require("@azure/keyvault-certificates"); const keyvaultSecret = require('@azure/keyvault-secrets'); const KV_URL = process.env["KEY_VAULT_URL"] || "ENTER_YOUR_KEY_VAULT_URL" const CERTIFICATE_NAME = process.env["CERTIFICATE_NAME"] || "ENTER_THE_NAME_OF_YOUR_CERTIFICATE_ON_KEY_VAULT"; // Initialize Azure SDKs const credential = new identity.DefaultAzureCredential(); const certClient = new keyvaultCert.CertificateClient(KV_URL, credential); const secretClient = new keyvaultSecret.SecretClient(KV_URL, credential); async function getKeyAndThumbprint() { // Grab the certificate thumbprint const certResponse = await certClient.getCertificate(CERTIFICATE_NAME).catch(err => console.log(err)); const thumbprint = certResponse.properties.x509Thumbprint.toString('hex') // When you upload a certificate to Key Vault, a secret containing your private key is automatically created const secretResponse = await secretClient.getSecret(CERTIFICATE_NAME).catch(err => console.log(err));; // secretResponse contains both public and private key, but we only need the private key const privateKey = secretResponse.value.split('-----BEGIN CERTIFICATE-----\n')[0] } getKeyAndThumbprint();
In your code, replace the placeholders:
-
ENTER_YOUR_KEY_VAULT_URL
with your Azure Key Vault URL. -
ENTER_THE_NAME_OF_YOUR_CERTIFICATE_ON_KEY_VAULT
with the name of your certificate in Azure Key Vault.
-
-
Use the
thumbprint
andprivateKey
values to update your configuration:let clientCert = { thumbprint: thumbprint, privateKey: privateKey, }; msalConfig.auth.clientCertificate = clientCert; //For this to work, you can't declares your msalConfig using const modifier
-
Then proceed to instantiate your confidential client as shown in the
getMsalInstance
method:class AuthProvider { //... getMsalInstance(msalConfig) { return new msal.ConfidentialClientApplication(msalConfig); } //... }
-
Use the steps in Run and test the web app to test your app.
Learn how to: