C# / .NET · recipe
Set up OPC UA certificates in C#
The application configuration owns your PKI. Point the four stores at persistent directories, keep AutoAcceptUntrustedCertificates false, and make sure the ApplicationUri matches the URI entry in your certificate's SAN.
| Stack | OPCFoundation/UA-.NETStandard |
|---|---|
| Version | 1.5.378.156 stable, 2.0.0-preview.2 |
The code
var application = new ApplicationInstance
{
ApplicationName = "MyOpcUaClient",
ApplicationType = ApplicationType.Client,
ApplicationConfiguration = await BuildConfigAsync(),
};
// create a self-signed application instance certificate if none exists
bool hasCert = await application.CheckApplicationInstanceCertificates(
silent: true, lifeTimeInMonths: 24);
if (!hasCert) throw new Exception("no application certificate and none could be created");
var config = application.ApplicationConfiguration;
// surface rejections instead of swallowing them
config.CertificateValidator.CertificateValidation += (sender, e) =>
{
Console.WriteLine($"peer certificate rejected: {e.Error.StatusCode}");
Console.WriteLine($" subject: {e.Certificate.Subject}");
e.Accept = false; // never blanket-accept in production
};
var endpoint = CoreClientUtils.SelectEndpoint(config, "opc.tcp://milo.digitalpetri.com:62541/milo", useSecurity: true);
Console.WriteLine($"policy: {endpoint.SecurityPolicyUri}");
Console.WriteLine($"mode : {endpoint.SecurityMode}");
var configured = new ConfiguredEndpoint(null, endpoint, EndpointConfiguration.Create(config));
using var session = await Session.Create(config, configured, false, "MyOpcUaClient", 60000,
new UserIdentity(new AnonymousIdentityToken()), null);
Console.WriteLine($"secure session: {session.Connected}");
What it prints
policy: http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256
mode : SignAndEncrypt
secure session: True
Notes
- CheckApplicationInstanceCertificates generates a self-signed certificate on first run, with the SAN entries derived from your ApplicationUri and hostname. Verify them afterwards rather than assuming.
- The CertificateValidation handler is how you find out why a peer was rejected. Log the status code and the subject; do not set e.Accept = true to make the problem disappear.
- In a container, ./pki must be a persistent volume. Otherwise the certificate is regenerated on every restart and every peer's trust list goes stale.
- The four stores are own, trusted, issuer and rejected. Intermediates go in issuer, not trusted.
- Set a certificate lifetime you will renew within, and diary it. An expired client certificate stops a line.
What breaks first
A CA-issued certificate is rejected even though the CA is trusted
Put the intermediate certificates in the issuer store. Also check the CA certificate carries keyCertSign and cRLSign: corporate CAs often do not.
BadCertificateChainIncompletePut the intermediate certificates in the issuer store. Also check the CA certificate carries keyCertSign and cRLSign: corporate CAs often do not.
Other recipes in this stack
Concepts on this page
Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.