Digital Signature
A digitalSignature block tells MPDEV to sign the produced packages and (almost) every executable file inside them. Signing is mandatory for production: Windows SmartScreen, MSIX install, the MSI updater, and the MSI contextMenu capability all require it.
Set digitalSignature in the common section to sign both MSI and MSIX, or inside msi / msix to sign just one output.
Three signing methods
The digitalSignature object is a oneOf of three shapes, distinguished by signWith:
signWith value | When to use it | Type definition |
|---|---|---|
"AzureTrustedSigning" | Recommended for production. Cloud signing with Microsoft's Trusted Signing service. No local cert handling. | AzureTrustedSigningSignature |
"Thumbprint" | You have a local cert with a private key in the Personal store. | ThumbprintSignature |
"GenerateTestCertificate" | Local development / CI tests only. MPDEV creates a fresh self-signed cert. Never ship to users. | TestCertificateSignature |
What gets signed
When digitalSignature is set, MPDEV automatically signs the produced installer and every file inside it whose extension is in this list:
.cab, .cat, .com, .dll, .exe, .js, .jse, .msi, .msp, .ocx, .ps1, .ps1xml, .psm1, .sys, .vbs, .vbe, .wsf
Already-signed files are not re-signed. Use exclusions to opt out of files that you specifically don't want signed.
"digitalSignature": {
"signWith": "AzureTrustedSigning",
…,
"exclusions": [
"source\\\\third-party\\\\already-signed\\.dll$",
"source\\\\external\\\\.+"
]
}
exclusions are regex patterns matched against file paths. Validation: valid regex.
1. Azure Trusted Signing
The modern, cert-less way to sign code. Microsoft hosts the certificate, you authenticate with an Azure identity, your installer is signed in the cloud.
"digitalSignature": {
"signWith": "AzureTrustedSigning",
"endpoint": "https://eus.codesigning.azure.net",
"codeSigningAccountName": "MySigningAccount",
"certificateProfileName": "MyProductionProfile",
"timestampServer": "http://timestamp.acs.microsoft.com",
"correlationId": "ci-build-12345",
"credentials": ["EnvironmentCredential", "AzureCliCredential"],
"exclusions": []
}
Properties
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
signWith | const | yes | – | Must be "AzureTrustedSigning". |
endpoint | URL | yes | – | The regional Trusted Signing endpoint, e.g., https://eus.codesigning.azure.net. |
codeSigningAccountName | string | yes | – | Your Trusted Signing account name. |
certificateProfileName | string | yes | – | The certificate profile name within the account. |
timestampServer | URL | yes | – | RFC 3161 timestamp server. Trusted Signing certs are 3-day valid – timestamping is mandatory. Recommended: http://timestamp.acs.microsoft.com. |
correlationId | string | no | – | Free-form ID to correlate sign requests in your build logs (e.g., CI build number). |
credentials | enum[] | no | ["EnvironmentCredential"] | Authentication methods tried in order. |
exclusions | string[] (regex) | no | – | Files to skip during file signing. |
Authentication
credentials is an array of credential types from Azure's DefaultAzureCredential chain. MPDEV tries them in order and uses the first one that works.
| Credential | How it authenticates |
|---|---|
EnvironmentCredential (default) | Reads AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET env vars. The standard CI option. |
ManagedIdentityCredential | Uses the VM/container's managed identity. |
WorkloadIdentityCredential | Federated workload identity (e.g., GitHub Actions OIDC). |
SharedTokenCacheCredential | Reuses tokens from the shared token cache. |
VisualStudioCredential | The signed-in Visual Studio account. |
AzureCliCredential | The currently logged-in az user. |
AzurePowerShellCredential | The currently logged-in Connect-AzAccount user. |
AzureDeveloperCliCredential | The currently logged-in azd user. |
InteractiveBrowserCredential | Pops up a browser sign-in. Last-resort for desktop dev. Useful for manual testing. |
For CI/CD set the three env vars and do not specify the
credentialsproperty:AZURE_TENANT_ID=...AZURE_CLIENT_ID=...AZURE_CLIENT_SECRET=...
Validation
The valid-azure-trusted-signing validator runs at build time and verifies that MPDEV can connect successfully to the Trusted Signing endpoint with the chosen credential chain. If your secrets are wrong, the build fails fast.
Rate limits: Trusted Signing has per-account rate limits. Throttle parallel CI jobs if you hit
429responses.
2. Local thumbprint
Use a certificate that is already imported into the Personal certificate store of the build account, identified by its thumbprint.
"digitalSignature": {
"signWith": "Thumbprint",
"thumbprint": "1A2B3C4D5E6F7081A2B3C4D5E6F708192A3B4C5D",
"timestampServer": "http://timestamp.sectigo.com",
"exclusions": []
}
Properties
| Property | Type | Required | Description |
|---|---|---|---|
signWith | const | yes | Must be "Thumbprint". |
thumbprint | string | yes | 40-character hex thumbprint (case insensitive) of an active certificate with a private key in the Personal store. |
timestampServer | URL | yes | RFC 3161 timestamp server. |
exclusions | string[] (regex) | no | Files to skip during file signing. |
Finding the thumbprint
- Open
certmgr.msc. - Navigate to Personal → Certificates.
- Double-click your code signing cert.
- Details tab → Thumbprint field. Copy the value, strip spaces.
Or via PowerShell:
Get-ChildItem -Path Cert:\CurrentUser\My | Format-List Subject, Thumbprint
Common timestamp servers
http://timestamp.acs.microsoft.com(Trusted Signing public TSA)http://timestamp.sectigo.comhttp://timestamp.comodoca.comhttp://timestamp.digicert.com
Validation
valid thumbprint– verifies the thumbprint matches a real, active cert with a private key in the Personal store.valid timestamp server– verifies the URL responds with HTTP 200.
3. Generate test certificate
For local development and CI smoke tests only. MPDEV creates a brand new self-signed certificate per build, signs everything with it, and you import it manually into the Trusted Root Certification Authorities store on test machines.
"digitalSignature": {
"signWith": "GenerateTestCertificate",
"timestampServer": "http://timestamp.sectigo.com"
}
Properties
| Property | Type | Required | Description |
|---|---|---|---|
signWith | const | yes | Must be "GenerateTestCertificate". |
timestampServer | URL | yes | RFC 3161 timestamp server. |
exclusions | string[] (regex) | no | Files to skip during file signing. |
The certificate's password is empty. It is dumped to a
.pfxfile in the build output for you to import on test machines. Never use this in production – Windows will not trust the cert without a manual import to Trusted Root.
Per-output signing
You can sign just one output by placing digitalSignature inside msi or msix:
{
"msi": {
"digitalSignature": {
"signWith": "Thumbprint",
"thumbprint": "…",
"timestampServer": "http://timestamp.sectigo.com"
}
},
"msix": {
"digitalSignature": {
"signWith": "GenerateTestCertificate",
"timestampServer": "http://timestamp.sectigo.com"
}
}
}
In the example above the MSI is signed by your real certificate and the MSIX is signed by an ephemeral test cert.
Capabilities that REQUIRE a digital signature
| Feature | Why |
|---|---|
| MSIX builds (any) | Windows refuses to install unsigned MSIX packages. (Test certs only after the cert is trusted on the install machine.) |
msi.contextMenu | Implemented as a sparse MSIX overlay that needs identity, hence a signature. |
msi.updater | The updater compares the new installer's signature against the installed one. Without digitalSignature there is nothing to compare. installDir must be under %ProgramFiles%. |
The corresponding validators are digital signature required - context menu and digital signature required - updater.
MSIX publisher must match the cert subject. When signing an MSIX with a real cert (Thumbprint or Trusted Signing), the certificate's Subject DN overrides
$.publisherfor MSIX identity – they must match for a successful install.