<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Vladimir Kocjancic</title>
    <description>The latest articles on Forem by Vladimir Kocjancic (@vkocjancic).</description>
    <link>https://forem.com/vkocjancic</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3755557%2F49bc5afd-f494-4370-8b5f-8286f6607143.jpg</url>
      <title>Forem: Vladimir Kocjancic</title>
      <link>https://forem.com/vkocjancic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/vkocjancic"/>
    <language>en</language>
    <item>
      <title>Certificate Pinning Pitfalls: Why Rotation Breaks Apps</title>
      <dc:creator>Vladimir Kocjancic</dc:creator>
      <pubDate>Thu, 05 Mar 2026 22:22:37 +0000</pubDate>
      <link>https://forem.com/vkocjancic/certificate-pinning-pitfalls-why-rotation-breaks-apps-4kko</link>
      <guid>https://forem.com/vkocjancic/certificate-pinning-pitfalls-why-rotation-breaks-apps-4kko</guid>
      <description>&lt;p&gt;You went and implemented certificate pinning in your app. You tested it and it worked perfectly. &lt;/p&gt;

&lt;p&gt;Fast forward a few months and your users cannot connect. You haven't changed the code for ages. So you check your API and it works fine, but your app? Not so much.&lt;/p&gt;

&lt;p&gt;The problem: certificate rotation. Something completely outside your control that managed to break your application. Most likely in the most awkward way and at the least desirable or expected time.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is certificate rotation?
&lt;/h2&gt;

&lt;p&gt;Certificate rotation is the process of replacing an existing certificate with a new one. Certificates require rotation for several reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Expiration&lt;/strong&gt; – some certificates expire more often than others (yes, I'm looking at you, Let's Encrypt)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revocation&lt;/strong&gt; – the certificate has been compromised or invalidated&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Algorithm upgrades&lt;/strong&gt; – moving from SHA-1 to SHA-256, for example&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain changes&lt;/strong&gt; – adding or removing domains from the certificate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Expiration you can plan for. Other rotations are silent, unpredictable. And by the time you notice, users have already noticed. By then, it's too late.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does my app break?
&lt;/h2&gt;

&lt;p&gt;Certificate pinning is based on a certificate's public key, hash, trust chain, or other metadata. When the certificate changes, some (if not all) of that data changes too—causing validation to fail.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Certificate hash and public key&lt;/strong&gt; change with each new certificate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trust chain&lt;/strong&gt; changes less frequently, but pinning &lt;em&gt;only&lt;/em&gt; the chain is insecure and weak. If you only check the chain, you're effectively accepting &lt;em&gt;any&lt;/em&gt; certificate from that chain. And that defeats the purpose of pinning.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What can I do to avoid downtime?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Set expiration reminders
&lt;/h3&gt;

&lt;p&gt;The easiest thing to do is set up calendar reminders for when your certificates expire. You can't fix what you don't know is expiring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pin the SPKI, not the whole certificate
&lt;/h3&gt;

&lt;p&gt;Some Certificate Authorities (CAs) allow renewal with the same key pair. If you control the server and configure this, the certificate's public key will remain unchanged. But by default, many renewals generate a new key.&lt;/p&gt;

&lt;p&gt;Still, pinning the &lt;strong&gt;Subject Public Key Info (SPKI)&lt;/strong&gt; is a decent solution. SPKI is the part of the certificate that contains the actual public key and its algorithm. Pinning this survives renewal &lt;em&gt;if the key pair stays the same&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Extract SPKI for pinning in .NET&lt;/span&gt;
&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;spki&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetPublicKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;spkiHash&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToBase64String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SHA256&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ComputeHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spki&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implement backup pins
&lt;/h3&gt;

&lt;p&gt;Keep at least two pins: the current certificate and a backup. You can use your CA's root or intermediate certificate for this. When rotation happens, your application still trusts the backup while you update the primary.&lt;/p&gt;

&lt;p&gt;Yes, you'll need to refresh the list over time. But your users won't experience downtime.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get notified before things break
&lt;/h3&gt;

&lt;p&gt;This is exactly why I'm building &lt;a href="https://certwatch.dev" rel="noopener noreferrer"&gt;CertWatch&lt;/a&gt;. The app tracks your certificates and alerts you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;90/60/30/14/7/1 days before expiry&lt;/li&gt;
&lt;li&gt;Immediately on unexpected rotation events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The alert includes the new public key so you can update your pinned app before it breaks. You'll know before your users do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Certificate pinning makes your app more secure. But without handling rotation, it makes your app brittle and prone to unexpected outages.&lt;/p&gt;

&lt;p&gt;Pin SPKI, keep backups, and set reminders. Do that, and you won't be waking up to a bunch of angry emails and calls in distress&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>security</category>
      <category>certificatepinning</category>
    </item>
    <item>
      <title>Implementing Certificate Pinning in .NET: A Step-by-Step Guide</title>
      <dc:creator>Vladimir Kocjancic</dc:creator>
      <pubDate>Thu, 05 Feb 2026 22:06:53 +0000</pubDate>
      <link>https://forem.com/vkocjancic/implementing-certificate-pinning-in-net-a-step-by-step-guide-72b</link>
      <guid>https://forem.com/vkocjancic/implementing-certificate-pinning-in-net-a-step-by-step-guide-72b</guid>
      <description>&lt;p&gt;Certificate pinning is a security technique where a client (like a mobile or desktop app) associates a specific server with an expected X.509 certificate or public key. When the client connects to the server, it verifies that the certificate presented matches the one it knows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Pin Certificates?
&lt;/h2&gt;

&lt;p&gt;The primary reason for pinning is to prevent man-in-the-middle (MITM) attacks where an attacker intercepts communication using a fake or invalid certificate. Pinning ensures your app only talks to a server you trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  The implementation
&lt;/h2&gt;

&lt;p&gt;We will create a simple command line application that fetches source code of my SaaS product web site &lt;a href="https://certwatch.dev" rel="noopener noreferrer"&gt;CertWatch&lt;/a&gt;. Why command line? Because, it is good enough example that will work everywhere else and because it is isolated enough that it is easy to follow even for a casual tech follower.&lt;/p&gt;

&lt;p&gt;The site uses Let's Encrypt certificate, that changes quite often, so beware that &lt;strong&gt;certificate public key used in this sample may not be valid at the time you read this article&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;First, we need to obtain public key of server certificate. We can do this by either viewing certificate in the browser or use a tool like openssl.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;g_ssPublicKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;       &lt;span class="s"&gt;"3082010A0282010100C4FFFFE6F3945AD2BF27D5DD674166130D5D2021CEFF0"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
&lt;span class="s"&gt;"4B06AD48F5F56A6245C590433121C8F08B7A565FBF38F1102917CB7434AFE91"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
&lt;span class="s"&gt;"18E2CB904BA723D57182B680B872CF05578B234F65DB1A39CD77DEBD07D0939"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
&lt;span class="s"&gt;"A0C440A9AE9245D0CAB59480DC3864D744BA6404B0D6DA9BAEE0E85CE0816D9"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
&lt;span class="s"&gt;"D7F43468D2E073CBA2EA10114323B0053F8AE29F86AD846B71FE4D7924494FB"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
&lt;span class="s"&gt;"0D80E3C78875085163B53121EBEBCF1356A4386DFF9E2CB93D0BD9CA3A39D4A"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
&lt;span class="s"&gt;"AC7BB34F2FF4AC70D59DBCD92254D48DE0BC3CCB4A8B4822D64CCE46F1E539B"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
&lt;span class="s"&gt;"116A00420825AD2AFF128F7A761D79186FB747761E47187BD527B1398F603DC"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
&lt;span class="s"&gt;"F7DCABD3535C28B7FB2C3068230203010001"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the program Main function, we will use &lt;code&gt;HttpClient&lt;/code&gt; to connect to the web site. In order to set certificate handling and verification, we must first declare &lt;code&gt;HttpClientHandler&lt;/code&gt;. The handler must do at least three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;enable Certificate Revocation List check to check that certificate has not been revoked&lt;/li&gt;
&lt;li&gt;set client certificate options to Manual, as we are going to manually validate certificate&lt;/li&gt;
&lt;li&gt;implement server certificate validation callback method to perform validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before we implement the callback method, let’s set a boiler plate for it and set first two items on the list. Validation method will return false and thus fail on every request.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClientHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
        &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CheckCertificateRevocationList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientCertificateOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ClientCertificateOption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Manual&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServerCertificateCustomValidationCallback&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sslPolicyErrors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Great. With that done, we can implement the body of the callback function. First, we need to check if the server web site certificate actually exists. If it doesn't we return false and print an error. Here, you would do some logging instead, but this is a demo app.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ERROR: No server certificate found"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next, we verify there are no SSL policy errors in certificate chain. If they are, we return false and print all policy errors.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sslPolicyErrors&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;SslPolicyErrors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"SSL Policy Errors: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sslPolicyErrors&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, we obtain, the public key of server certificate and check if it matches the one, we declared in our app. If there is no match, we again print an error and return false. If public keys match, then the certificate is correct and we successfully end validation.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;sPublicKeyToVerify&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetPublicKeyString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_ssPublicKey&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;sPublicKeyToVerify&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ERROR: Certificate public key mismatch"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Certificate public key matches"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now, all we have to do, is call our website and print it's source code. The validation procedure will run immediately after SSL handshake is established.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;sResponse&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStringAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://certwatch.dev"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In less than 50 lines of code, we have implemented a working, robust certificate pinning that ensures our app only communicates with our genuine API server. This simple technique significantly raises the bar against possible man-in-the-middle attacks.&lt;/p&gt;

&lt;p&gt;Complete working example is embedded below. If you cannot see it, it is also published as &lt;a href="https://gist.github.com/vkocjancic/eafd96dee3b6097d22db67483793cda9" rel="noopener noreferrer"&gt;gist on Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;h2&gt;
  
  
  The Operational Challenge
&lt;/h2&gt;

&lt;p&gt;While the code is straightforward, the ongoing management of pinned certificates is not. Teams must track expiry dates, coordinate rotations, and update client apps. This usually ends up as a manual process, which is prone to error and often the cause of preventable outages.&lt;/p&gt;

&lt;p&gt;If managing this process across multiple APIs feels like a burden that is likely to cause a production incident, you might be interested in &lt;a href="https://certwatch.dev" rel="noopener noreferrer"&gt;CertWatch&lt;/a&gt;, a tool I'm building to automate SSL certificate monitoring and alerting.&lt;/p&gt;




&lt;p&gt;This article was originally published on &lt;a href="https://lotushints.com" rel="noopener noreferrer"&gt;lotushints.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>devops</category>
      <category>security</category>
    </item>
  </channel>
</rss>
