Code Signing for Visual Studio ClickOnce Deployments
ClickOnce is still a great deployment story for Windows line-of-business apps — until code signing enters the picture. EV certificates on USB tokens prompt for a PIN on every manifest signature, which kills automated publishing. Here's the clean way out.
Why ClickOnce Signing Hurts
- Visual Studio signs manifests during publish — each signature triggers the token's PIN dialog.
- CI machines have no interactive session, so the dialog hangs the build forever.
- Timestamp server hiccups fail the whole publish.
- Vendor cloud tools bolt on subscriptions and per-signature fees for what is fundamentally a local operation.
The Pattern: Build Unsigned, Sign After
- Publish the ClickOnce output without signing (or with a temporary self-signed cert).
- Sign the real binaries —
setup.exe, the application.exe, your DLLs — through OneSigner, which handles PIN entry and timestamping automatically. - Re-generate/update manifests where required (Mage) and deploy.
Signing the files
# Application executable
curl -sf -X POST "http://localhost:9440/api/upload?download=true" \
-H "Authorization: Bearer TOKEN" \
-F "file=@publish/MyApp.exe" -o publish/MyApp.exe
# Bootstrapper
curl -sf -X POST "http://localhost:9440/api/upload?download=true" \
-H "Authorization: Bearer TOKEN" \
-F "file=@publish/setup.exe" -o publish/setup.exe
MSBuild hook
<Target Name="SignAfterPublish" AfterTargets="Publish">
<Exec Command="curl -sf -X POST "http://localhost:9440/api/upload?download=true" -H "Authorization: Bearer $(OneSignerToken)" -F "file=@$(PublishDir)$(TargetFileName)" -o "$(PublishDir)$(TargetFileName)"" />
</Target>
Alternative: signtool-Style CLI
Prefer classic tooling? OneSigner's CLI takes signtool-compatible flags with automated PIN entry:
OneSignerService.exe --codesign /sha1 THUMBPRINT /pin PIN /fd sha256 ^
/tr http://ts.ssl.com /td sha256 /d "MyApp" publish\MyApp.exe
Or sign from a build machine that doesn't host the token via OneSignTool — AzureSignTool-compatible, hash-only transfer.
Why Not a Cloud Signing Service?
They work — at the price of a subscription, per-signature fees, network dependency in every publish, and lock-in to one CA's tooling. A token plus a perpetual OneSigner license does the same job locally, with your existing certificate from any CA, at zero marginal cost. Full cost analysis: USB Token vs Cloud HSM.
Checklist
- Sign setup.exe and the app exe at minimum; users see both.
- Always timestamp (
/tr+/td sha256). - Verify with
signtool verify /pa /vbefore deploying the update feed.