<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>PKI on IAMDevBox</title><link>https://www.iamdevbox.com/tags/pki/</link><description>Recent content in PKI on IAMDevBox</description><image><title>IAMDevBox</title><url>https://www.iamdevbox.com/IAMDevBox.com.jpg</url><link>https://www.iamdevbox.com/IAMDevBox.com.jpg</link></image><generator>Hugo -- 0.146.0</generator><language>en-us</language><lastBuildDate>Thu, 25 Jun 2026 20:10:39 -0400</lastBuildDate><atom:link href="https://www.iamdevbox.com/tags/pki/index.xml" rel="self" type="application/rss+xml"/><item><title>Post-Quantum Cryptography Migration for Identity Infrastructure: 2026 Developer Guide</title><link>https://www.iamdevbox.com/posts/post-quantum-cryptography-migration-identity-infrastructure-2026/</link><pubDate>Thu, 25 Jun 2026 20:00:00 +0000</pubDate><guid>https://www.iamdevbox.com/posts/post-quantum-cryptography-migration-identity-infrastructure-2026/</guid><description>Migrate your identity infrastructure to post-quantum cryptography before the 2030 federal deadline. Covers NIST ML-KEM/ML-DSA standards, Keycloak PQC JWT signing, TLS hybrid migration, and JWT/SAML signing for OAuth 2.0 systems.</description><content:encoded><![CDATA[<p>A June 22, 2026 U.S. executive order mandates all federal agencies and their vendors complete migration to NIST post-quantum cryptographic standards by December 31, 2030. If your identity infrastructure handles government workloads — or if competitors start advertising PQC compliance — you need a concrete migration plan now. This guide covers the specific algorithms, migration sequence, and platform-specific steps for OAuth, JWT, SAML, and TLS in identity systems.</p>
<h2 id="why-identity-infrastructure-is-a-priority-target">Why Identity Infrastructure Is a Priority Target</h2>
<p>Identity systems are the highest-risk category for post-quantum attacks for two reasons:</p>
<p><strong>Long-lived credentials.</strong> TLS certificates, SAML signing certificates, and OAuth client secrets often have multi-year lifetimes. A certificate issued today with RSA-2048 will still be in production when quantum computers become capable — and adversaries are harvesting encrypted traffic now to decrypt it retroactively (&ldquo;harvest now, decrypt later&rdquo;).</p>
<p><strong>High-value targets.</strong> Compromising an OAuth authorization server, SAML IdP, or certificate authority yields persistent access to every downstream service. This makes identity infrastructure more valuable to harvest than application data.</p>
<p>The immediate threat is not &ldquo;quantum computers can break RSA today.&rdquo; The threat is: <strong>traffic captured today will be decryptable within 5-10 years.</strong> For OAuth tokens and SAML assertions with long-lived session data, that window matters.</p>
<h2 id="nist-post-quantum-standards-what-to-use">NIST Post-Quantum Standards: What to Use</h2>
<p>NIST finalized three standards in August 2024 that are relevant for identity:</p>
<table>
  <thead>
      <tr>
          <th>Standard</th>
          <th>Algorithm</th>
          <th>Use Case</th>
          <th>Signature Size</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>FIPS 203</td>
          <td>ML-KEM (CRYSTALS-Kyber)</td>
          <td>Key encapsulation / TLS key exchange</td>
          <td>N/A (KEM)</td>
      </tr>
      <tr>
          <td>FIPS 204</td>
          <td>ML-DSA (CRYSTALS-Dilithium)</td>
          <td>Digital signatures: JWT, SAML, certificates</td>
          <td>~2-3 KB (Level 2)</td>
      </tr>
      <tr>
          <td>FIPS 205</td>
          <td>SLH-DSA (SPHINCS+)</td>
          <td>Digital signatures, stateless hash-based</td>
          <td>8-49 KB</td>
      </tr>
  </tbody>
</table>
<p><strong>For identity systems:</strong></p>
<ul>
<li><strong>JWT and SAML signing</strong> → ML-DSA (FIPS 204). Use Level 2 (ML-DSA-44) for performance; Level 3 (ML-DSA-65) for high-security environments.</li>
<li><strong>TLS key exchange</strong> → ML-KEM (FIPS 203). Deploy as hybrid with X25519 during migration.</li>
<li><strong>Avoid SLH-DSA</strong> for high-frequency operations — 8-49 KB signatures will degrade JWT Bearer token performance significantly. Reserve it for certificate root signing where frequency is low.</li>
</ul>
<h2 id="migration-sequence-tls-first-signatures-second">Migration Sequence: TLS First, Signatures Second</h2>
<p>Migrate in this order:</p>
<ol>
<li><strong>Hybrid PQC TLS</strong> (do first — protects against HNDL immediately)</li>
<li><strong>CA certificate upgrade</strong> (intermediate and root CAs to ML-DSA)</li>
<li><strong>IdP signing key migration</strong> (SAML IdP certificates, JWT signing keys)</li>
<li><strong>Client credential migration</strong> (mTLS client certs for service-to-service OAuth)</li>
<li><strong>Token format updates</strong> (algorithm identifiers in JWT headers)</li>
</ol>
<h3 id="phase-1-hybrid-post-quantum-tls">Phase 1: Hybrid Post-Quantum TLS</h3>
<p>Deploy hybrid cipher suites that combine classical ECDH with ML-KEM. This maintains compatibility with clients that don&rsquo;t support PQC while protecting against HNDL.</p>
<p><strong>Nginx with OQS Provider:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Install Open Quantum Safe provider for OpenSSL 3.3+</span>
</span></span><span style="display:flex;"><span>apt-get install liboqs-dev
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Or build from: https://github.com/open-quantum-safe/liboqs</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># nginx.conf server block</span>
</span></span><span style="display:flex;"><span>server <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    listen <span style="color:#ae81ff">443</span> ssl;
</span></span><span style="display:flex;"><span>    ssl_certificate /etc/ssl/hybrid-cert.pem;
</span></span><span style="display:flex;"><span>    ssl_certificate_key /etc/ssl/hybrid-key.pem;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># Hybrid PQC: prefer X25519Kyber768, fall back to classical</span>
</span></span><span style="display:flex;"><span>    ssl_ecdh_curve X25519Kyber768:X25519:prime256v1;
</span></span><span style="display:flex;"><span>    ssl_protocols TLSv1.3;
</span></span><span style="display:flex;"><span>    ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p><strong>HAProxy 2.9+:</strong></p>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 504 105"
      >
      <g transform='translate(8,16)'>
<text text-anchor='middle' x='0' y='4' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='0' y='68' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='8' y='4' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='8' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='16' y='4' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='16' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='24' y='4' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='24' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='32' y='4' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='32' y='20' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='32' y='36' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='32' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='32' y='84' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='40' y='4' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='40' y='20' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='40' y='36' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='40' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='40' y='84' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='48' y='36' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='48' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='48' y='84' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='56' y='20' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='56' y='36' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='56' y='68' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='56' y='84' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='64' y='36' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='72' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='72' y='36' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='72' y='68' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='72' y='84' fill='currentColor' style='font-size:1em'>*</text>
<text text-anchor='middle' x='80' y='20' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='80' y='36' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='80' y='68' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='80' y='84' fill='currentColor' style='font-size:1em'>:</text>
<text text-anchor='middle' x='88' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='88' y='36' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='88' y='84' fill='currentColor' style='font-size:1em'>4</text>
<text text-anchor='middle' x='96' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='96' y='36' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'>_</text>
<text text-anchor='middle' x='96' y='84' fill='currentColor' style='font-size:1em'>4</text>
<text text-anchor='middle' x='104' y='20' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='104' y='36' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='104' y='84' fill='currentColor' style='font-size:1em'>3</text>
<text text-anchor='middle' x='112' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='112' y='36' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='112' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='120' y='36' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='120' y='84' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='128' y='36' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='128' y='84' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='136' y='36' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='136' y='84' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='144' y='36' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='152' y='36' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='152' y='84' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='160' y='36' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='160' y='84' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='168' y='36' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='168' y='84' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='176' y='36' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='184' y='36' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='184' y='84' fill='currentColor' style='font-size:1em'>/</text>
<text text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='192' y='36' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='192' y='84' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='200' y='36' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='200' y='84' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='208' y='36' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='208' y='84' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='216' y='36' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='216' y='84' fill='currentColor' style='font-size:1em'>/</text>
<text text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'>X</text>
<text text-anchor='middle' x='224' y='84' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='232' y='36' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='232' y='84' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'>5</text>
<text text-anchor='middle' x='240' y='36' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='240' y='84' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='248' y='20' fill='currentColor' style='font-size:1em'>5</text>
<text text-anchor='middle' x='248' y='36' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='248' y='84' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='256' y='20' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='256' y='36' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='256' y='84' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'>9</text>
<text text-anchor='middle' x='264' y='36' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='264' y='84' fill='currentColor' style='font-size:1em'>x</text>
<text text-anchor='middle' x='272' y='20' fill='currentColor' style='font-size:1em'>K</text>
<text text-anchor='middle' x='272' y='36' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='272' y='84' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='280' y='20' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='280' y='36' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='280' y='84' fill='currentColor' style='font-size:1em'>/</text>
<text text-anchor='middle' x='288' y='20' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='288' y='36' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='288' y='84' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='296' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='296' y='36' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='296' y='84' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='304' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='304' y='36' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='304' y='84' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='312' y='20' fill='currentColor' style='font-size:1em'>7</text>
<text text-anchor='middle' x='312' y='36' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='312' y='84' fill='currentColor' style='font-size:1em'>.</text>
<text text-anchor='middle' x='320' y='20' fill='currentColor' style='font-size:1em'>6</text>
<text text-anchor='middle' x='320' y='84' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='328' y='20' fill='currentColor' style='font-size:1em'>8</text>
<text text-anchor='middle' x='328' y='36' fill='currentColor' style='font-size:1em'>T</text>
<text text-anchor='middle' x='328' y='84' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='336' y='20' fill='currentColor' style='font-size:1em'>D</text>
<text text-anchor='middle' x='336' y='36' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='336' y='84' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='344' y='20' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='344' y='36' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='352' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='352' y='36' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='360' y='20' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='360' y='36' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='368' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='368' y='36' fill='currentColor' style='font-size:1em'>.</text>
<text text-anchor='middle' x='376' y='20' fill='currentColor' style='font-size:1em'>0</text>
<text text-anchor='middle' x='376' y='36' fill='currentColor' style='font-size:1em'>3</text>
<text text-anchor='middle' x='384' y='20' fill='currentColor' style='font-size:1em'>0</text>
<text text-anchor='middle' x='392' y='20' fill='currentColor' style='font-size:1em'>:</text>
<text text-anchor='middle' x='400' y='20' fill='currentColor' style='font-size:1em'>X</text>
<text text-anchor='middle' x='408' y='20' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='416' y='20' fill='currentColor' style='font-size:1em'>5</text>
<text text-anchor='middle' x='424' y='20' fill='currentColor' style='font-size:1em'>5</text>
<text text-anchor='middle' x='432' y='20' fill='currentColor' style='font-size:1em'>1</text>
<text text-anchor='middle' x='440' y='20' fill='currentColor' style='font-size:1em'>9</text>
<text text-anchor='middle' x='448' y='20' fill='currentColor' style='font-size:1em'>:</text>
<text text-anchor='middle' x='456' y='20' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='464' y='20' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='472' y='20' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='480' y='20' fill='currentColor' style='font-size:1em'>5</text>
<text text-anchor='middle' x='488' y='20' fill='currentColor' style='font-size:1em'>6</text>
</g>

    </svg>
  
</div>
<p><strong>Verify hybrid TLS is active:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>openssl s_client -connect your-idp.example.com:443 <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -groups X25519Kyber768Draft00:X25519 2&gt;&amp;<span style="color:#ae81ff">1</span> | grep <span style="color:#e6db74">&#34;Server Temp Key&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Expected: Server Temp Key: X25519Kyber768, 1184 bits</span>
</span></span></code></pre></div><h3 id="phase-2-keycloak-post-quantum-jwt-signing">Phase 2: Keycloak Post-Quantum JWT Signing</h3>
<p>Keycloak 26+ supports custom key providers via the <code>KeyProvider</code> SPI, which allows plugging in ML-DSA signing keys alongside existing RSA/EC keys.</p>
<p><strong>Step 1: Add Bouncy Castle FIPS provider</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Download bc-fips-2.0.0.jar and bctls-fips-2.0.19.jar</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># from https://www.bouncycastle.org/fips-java/</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cp bc-fips-2.0.0.jar $KEYCLOAK_HOME/providers/
</span></span><span style="display:flex;"><span>cp bctls-fips-2.0.19.jar $KEYCLOAK_HOME/providers/
</span></span></code></pre></div><p><strong>Step 2: Register the ML-DSA key in Admin Console</strong></p>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 648 153"
      >
      <g transform='translate(8,16)'>
<path d='M 92,56 L 100,40' fill='none' stroke='currentColor'></path>
<text text-anchor='middle' x='0' y='4' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='0' y='36' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='8' y='4' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='8' y='36' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='16' y='4' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='16' y='36' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='16' y='52' fill='currentColor' style='font-size:1em'>K</text>
<text text-anchor='middle' x='16' y='68' fill='currentColor' style='font-size:1em'>K</text>
<text text-anchor='middle' x='16' y='84' fill='currentColor' style='font-size:1em'>K</text>
<text text-anchor='middle' x='16' y='100' fill='currentColor' style='font-size:1em'>K</text>
<text text-anchor='middle' x='16' y='116' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='16' y='132' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='24' y='4' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='24' y='36' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='24' y='52' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='24' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='24' y='84' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='24' y='100' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='24' y='116' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='24' y='132' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='32' y='4' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='32' y='36' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='32' y='52' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='32' y='68' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='32' y='84' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='32' y='100' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='32' y='116' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='32' y='132' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='40' y='36' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='40' y='52' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='40' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='40' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='40' y='132' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='48' y='4' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='48' y='36' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='48' y='52' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='48' y='68' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='48' y='84' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='48' y='100' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='48' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='48' y='132' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='56' y='4' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='56' y='36' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='56' y='52' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='56' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='56' y='84' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='56' y='100' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='56' y='116' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='56' y='132' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='64' y='4' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='64' y='52' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='64' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='64' y='84' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='64' y='100' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='64' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='64' y='132' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='72' y='4' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='72' y='36' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='72' y='52' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='72' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='72' y='84' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='72' y='100' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='72' y='116' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='72' y='132' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='80' y='4' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='80' y='36' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='80' y='52' fill='currentColor' style='font-size:1em'>:</text>
<text text-anchor='middle' x='80' y='84' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='80' y='100' fill='currentColor' style='font-size:1em'>w</text>
<text text-anchor='middle' x='80' y='116' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='80' y='132' fill='currentColor' style='font-size:1em'>:</text>
<text text-anchor='middle' x='88' y='4' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='88' y='36' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='88' y='84' fill='currentColor' style='font-size:1em'>:</text>
<text text-anchor='middle' x='88' y='100' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='88' y='116' fill='currentColor' style='font-size:1em'>:</text>
<text text-anchor='middle' x='96' y='4' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='96' y='36' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='96' y='100' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='96' y='132' fill='currentColor' style='font-size:1em'>2</text>
<text text-anchor='middle' x='104' y='36' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='104' y='52' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='104' y='84' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='104' y='100' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='104' y='116' fill='currentColor' style='font-size:1em'>M</text>
<text text-anchor='middle' x='104' y='132' fill='currentColor' style='font-size:1em'>0</text>
<text text-anchor='middle' x='112' y='4' fill='currentColor' style='font-size:1em'>→</text>
<text text-anchor='middle' x='112' y='36' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='112' y='52' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='112' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='112' y='84' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='112' y='100' fill='currentColor' style='font-size:1em'>:</text>
<text text-anchor='middle' x='112' y='116' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='112' y='132' fill='currentColor' style='font-size:1em'>0</text>
<text text-anchor='middle' x='120' y='36' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='120' y='52' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'>w</text>
<text text-anchor='middle' x='120' y='84' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='120' y='116' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='128' y='4' fill='currentColor' style='font-size:1em'>R</text>
<text text-anchor='middle' x='128' y='36' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='128' y='52' fill='currentColor' style='font-size:1em'>/</text>
<text text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='128' y='84' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='128' y='100' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='128' y='116' fill='currentColor' style='font-size:1em'>D</text>
<text text-anchor='middle' x='136' y='4' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='136' y='36' fill='currentColor' style='font-size:1em'>:</text>
<text text-anchor='middle' x='136' y='52' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='136' y='84' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='136' y='100' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='136' y='116' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='136' y='132' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='144' y='4' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='144' y='52' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='144' y='84' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='144' y='100' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='144' y='116' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='144' y='132' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='152' y='4' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='152' y='52' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'>:</text>
<text text-anchor='middle' x='152' y='84' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='152' y='100' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='152' y='116' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='152' y='132' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='160' y='4' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='160' y='52' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='160' y='84' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='160' y='100' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='160' y='116' fill='currentColor' style='font-size:1em'>4</text>
<text text-anchor='middle' x='160' y='132' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='168' y='52' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='168' y='84' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='168' y='116' fill='currentColor' style='font-size:1em'>4</text>
<text text-anchor='middle' x='168' y='132' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='176' y='4' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='176' y='52' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='176' y='84' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='176' y='100' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='176' y='132' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='184' y='4' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='184' y='52' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='184' y='84' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='184' y='100' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='184' y='132' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='192' y='4' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='192' y='52' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='192' y='84' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='192' y='100' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='200' y='4' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='200' y='52' fill='currentColor' style='font-size:1em'>/</text>
<text text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='200' y='84' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='200' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='200' y='132' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='208' y='4' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='208' y='52' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='208' y='84' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='208' y='100' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='208' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='208' y='132' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='216' y='4' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='216' y='52' fill='currentColor' style='font-size:1em'>q</text>
<text text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='216' y='84' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='216' y='100' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='216' y='132' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='224' y='4' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='224' y='52' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='224' y='84' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='224' y='100' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='224' y='116' fill='currentColor' style='font-size:1em'>M</text>
<text text-anchor='middle' x='224' y='132' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='232' y='4' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='232' y='52' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='232' y='84' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='232' y='100' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='232' y='116' fill='currentColor' style='font-size:1em'>L</text>
<text text-anchor='middle' x='240' y='52' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='240' y='84' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='240' y='100' fill='currentColor' style='font-size:1em'>w</text>
<text text-anchor='middle' x='240' y='116' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='240' y='132' fill='currentColor' style='font-size:1em'>R</text>
<text text-anchor='middle' x='248' y='4' fill='currentColor' style='font-size:1em'>→</text>
<text text-anchor='middle' x='248' y='52' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'>w</text>
<text text-anchor='middle' x='248' y='100' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='248' y='116' fill='currentColor' style='font-size:1em'>D</text>
<text text-anchor='middle' x='248' y='132' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='256' y='52' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='256' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='256' y='100' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='256' y='116' fill='currentColor' style='font-size:1em'>S</text>
<text text-anchor='middle' x='256' y='132' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='264' y='4' fill='currentColor' style='font-size:1em'>K</text>
<text text-anchor='middle' x='264' y='52' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='264' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='264' y='100' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='264' y='116' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='272' y='4' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='272' y='52' fill='currentColor' style='font-size:1em'>/</text>
<text text-anchor='middle' x='272' y='68' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='272' y='100' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='272' y='116' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='272' y='132' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='280' y='4' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='280' y='52' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='280' y='68' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='280' y='116' fill='currentColor' style='font-size:1em'>6</text>
<text text-anchor='middle' x='280' y='132' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='288' y='4' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='288' y='52' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='288' y='116' fill='currentColor' style='font-size:1em'>5</text>
<text text-anchor='middle' x='288' y='132' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='296' y='52' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='304' y='4' fill='currentColor' style='font-size:1em'>→</text>
<text text-anchor='middle' x='304' y='52' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='304' y='116' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='304' y='132' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='312' y='52' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='312' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='312' y='132' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='320' y='4' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='320' y='52' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='320' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='328' y='4' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='328' y='52' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='328' y='132' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='336' y='4' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='336' y='52' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='336' y='116' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='336' y='132' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='344' y='4' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='344' y='52' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='344' y='116' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='344' y='132' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='352' y='4' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='352' y='52' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='352' y='116' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='352' y='132' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='360' y='4' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='360' y='52' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='360' y='116' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='368' y='4' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='368' y='52' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='368' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='368' y='132' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='376' y='4' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='376' y='52' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='376' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='376' y='132' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='384' y='4' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='384' y='52' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='392' y='52' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='392' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='392' y='132' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='400' y='4' fill='currentColor' style='font-size:1em'>→</text>
<text text-anchor='middle' x='400' y='52' fill='currentColor' style='font-size:1em'>.</text>
<text text-anchor='middle' x='400' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='400' y='132' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='408' y='52' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='408' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='408' y='132' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='416' y='4' fill='currentColor' style='font-size:1em'>A</text>
<text text-anchor='middle' x='416' y='52' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='416' y='116' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='416' y='132' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='424' y='4' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='424' y='52' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='424' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='424' y='132' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='432' y='4' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='432' y='52' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='432' y='116' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='432' y='132' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='440' y='52' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='440' y='116' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='440' y='132' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='448' y='4' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='448' y='116' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='448' y='132' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='456' y='4' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='456' y='116' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='464' y='4' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='472' y='4' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='480' y='4' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='488' y='4' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='496' y='4' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='504' y='4' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='520' y='4' fill='currentColor' style='font-size:1em'>→</text>
<text text-anchor='middle' x='536' y='4' fill='currentColor' style='font-size:1em'>j</text>
<text text-anchor='middle' x='544' y='4' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='552' y='4' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='560' y='4' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='568' y='4' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='576' y='4' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='584' y='4' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='592' y='4' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='600' y='4' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='608' y='4' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='616' y='4' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='624' y='4' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='632' y='4' fill='currentColor' style='font-size:1em'>e</text>
</g>

    </svg>
  
</div>
<p><strong>Step 3: Generate the ML-DSA keystore</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>keytool -genkeypair <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -alias ml-dsa-signing-key <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -keyalg ML-DSA-44 <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -keystore /opt/keycloak/pqc-keys/ml-dsa-keystore.bcfks <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -storetype BCFKS <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -providerpath /opt/keycloak/providers/bc-fips-2.0.0.jar <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -dname <span style="color:#e6db74">&#34;CN=Keycloak PQC Signing Key, O=Corp, C=US&#34;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -validity <span style="color:#ae81ff">1095</span>
</span></span></code></pre></div><p><strong>Step 4: Verify JWT algorithm in issued tokens</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Get a token and decode the header</span>
</span></span><span style="display:flex;"><span>curl -s -X POST https://keycloak.example.com/realms/master/protocol/openid-connect/token <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -d <span style="color:#e6db74">&#34;client_id=test-client&amp;client_secret=secret&amp;grant_type=client_credentials&#34;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  | jq -r <span style="color:#e6db74">&#39;.access_token&#39;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  | cut -d. -f1 <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  | base64 -d 2&gt;/dev/null <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  | jq .
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Expected: { &#34;alg&#34;: &#34;ML-DSA-44&#34;, &#34;kid&#34;: &#34;...&#34;, &#34;typ&#34;: &#34;JWT&#34; }</span>
</span></span></code></pre></div><p>During the transition period, Keycloak will issue tokens with ML-DSA while keeping RSA-256 as a fallback for clients that don&rsquo;t yet support the new algorithm. Clients validate using the <code>kid</code> header to fetch the correct public key from the JWKS endpoint.</p>
<h3 id="phase-3-saml-idp-certificate-migration">Phase 3: SAML IdP Certificate Migration</h3>
<p>SAML signing certificates use RSA or EC. The migration path:</p>
<ol>
<li><strong>Generate hybrid certificate</strong> with ML-DSA as the primary algorithm</li>
<li><strong>Add new certificate to IdP metadata</strong> alongside the existing RSA cert (dual-key operation)</li>
<li><strong>Update SP metadata</strong> on each relying party to trust both certificates</li>
<li><strong>Monitor</strong> SP assertion validation for 30 days</li>
<li><strong>Remove</strong> the RSA certificate once all SPs have updated</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Generate ML-DSA SAML signing certificate using OpenSSL 3.3+ with OQS</span>
</span></span><span style="display:flex;"><span>openssl req -x509 -newkey ml-dsa-44 <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -keyout saml-signing-key-pqc.pem <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -out saml-signing-cert-pqc.pem <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -days <span style="color:#ae81ff">1095</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -subj <span style="color:#e6db74">&#34;/CN=SAML IdP PQC Signing/O=Corp/C=US&#34;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -nodes
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Verify the certificate algorithm</span>
</span></span><span style="display:flex;"><span>openssl x509 -in saml-signing-cert-pqc.pem -text -noout | grep <span style="color:#e6db74">&#34;Signature Algorithm&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Expected: Signature Algorithm: ML-DSA-44</span>
</span></span></code></pre></div><p>For ForgeRock AM, upload the new PQC certificate under:
<code>Admin Console → Realms → Federation → SAML 2.0 → Signing and Encryption → Add New Signing Certificate</code></p>
<h3 id="phase-4-auth0-and-okta--current-state">Phase 4: Auth0 and Okta — Current State</h3>
<p>As of June 2026, managed identity providers have limited PQC support:</p>
<table>
  <thead>
      <tr>
          <th>Provider</th>
          <th>PQC TLS</th>
          <th>ML-DSA JWT Signing</th>
          <th>Timeline</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Auth0</td>
          <td>Partial (Cloudflare hybrid)</td>
          <td>Not supported</td>
          <td>2027-2028 roadmap</td>
      </tr>
      <tr>
          <td>Okta</td>
          <td>Partial (Fastly edge)</td>
          <td>Not supported</td>
          <td>2027-2028 roadmap</td>
      </tr>
      <tr>
          <td>Microsoft Entra ID</td>
          <td>X25519Kyber768 (preview)</td>
          <td>Not supported</td>
          <td>FY2027</td>
      </tr>
      <tr>
          <td>Ping Identity</td>
          <td>Available in PingFederate 12.2+</td>
          <td>ML-DSA-44 available</td>
          <td>Now</td>
      </tr>
      <tr>
          <td>Keycloak 26+</td>
          <td>Via OQS provider</td>
          <td>ML-DSA-44 via Bouncy Castle</td>
          <td>Now</td>
      </tr>
  </tbody>
</table>
<p><strong>For Auth0/Okta deployments:</strong> Apply PQC at the infrastructure layer:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># Apply post-quantum TLS at your API gateway (Kong, Nginx, Envoy)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Even if Auth0/Okta don&#39;t support ML-DSA JWT signing yet,</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># securing your Auth0 Management API calls and callback flows</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># with hybrid PQC TLS protects against HNDL.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Envoy filter chain example</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">transport_socket</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">name</span>: <span style="color:#ae81ff">envoy.transport_sockets.tls</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">typed_config</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;@type&#34;: </span><span style="color:#ae81ff">type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">common_tls_context</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">tls_params</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">tls_minimum_protocol_version</span>: <span style="color:#ae81ff">TLSv1_3</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">ecdh_curves</span>:
</span></span><span style="display:flex;"><span>          - <span style="color:#ae81ff">X25519Kyber768Draft00</span>
</span></span><span style="display:flex;"><span>          - <span style="color:#ae81ff">X25519</span>
</span></span></code></pre></div><h2 id="hybrid-migration-running-old-and-new-simultaneously">Hybrid Migration: Running Old and New Simultaneously</h2>
<p>During the 2-4 year migration window, you&rsquo;ll run classical and PQC algorithms in parallel. Key principles:</p>
<p><strong>Dual-key JWKS endpoint</strong> — Publish both RSA-256 and ML-DSA-44 public keys. Clients use the <code>kid</code> header to select the right key. New clients can be updated to prefer ML-DSA; legacy clients fall back to RSA.</p>
<p><strong>Downgrade detection</strong> — Log which <code>kid</code> values are being used in token validation. If ML-DSA tokens are being validated, the client supports PQC. Track the ratio to measure migration progress.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># Track algorithm usage in your token validation middleware</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">validate_token</span>(token: str) <span style="color:#f92672">-&gt;</span> dict:
</span></span><span style="display:flex;"><span>    header <span style="color:#f92672">=</span> jwt<span style="color:#f92672">.</span>get_unverified_header(token)
</span></span><span style="display:flex;"><span>    alg <span style="color:#f92672">=</span> header<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;alg&#34;</span>, <span style="color:#e6db74">&#34;unknown&#34;</span>)
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># Emit metric for algorithm usage tracking</span>
</span></span><span style="display:flex;"><span>    metrics<span style="color:#f92672">.</span>increment(<span style="color:#e6db74">&#34;jwt.validation&#34;</span>, tags<span style="color:#f92672">=</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;algorithm&#34;</span>: alg,
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;is_pqc&#34;</span>: alg<span style="color:#f92672">.</span>startswith(<span style="color:#e6db74">&#34;ML-&#34;</span>)
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># Validate using appropriate key</span>
</span></span><span style="display:flex;"><span>    jwks <span style="color:#f92672">=</span> fetch_jwks(header[<span style="color:#e6db74">&#34;kid&#34;</span>])
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> jwt<span style="color:#f92672">.</span>decode(token, jwks, algorithms<span style="color:#f92672">=</span>[alg])
</span></span></code></pre></div><p><strong>Certificate dual-signing</strong> — Some PKI vendors (DigiCert, Entrust) now offer dual-algorithm certificates that include both an RSA and ML-DSA public key. This eliminates the dual-key complexity but requires client support for parsing dual-cert structures.</p>
<h2 id="compliance-checklist-for-the-2030-deadline">Compliance Checklist for the 2030 Deadline</h2>
<table>
  <thead>
      <tr>
          <th>Item</th>
          <th>Action</th>
          <th>Priority</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TLS to hybrid PQC</td>
          <td>Deploy X25519+Kyber768 on IdP endpoints</td>
          <td>🔴 Immediate</td>
      </tr>
      <tr>
          <td>Inventory RSA/ECC usage</td>
          <td><code>openssl s_client</code> scan all IdP endpoints</td>
          <td>🔴 Immediate</td>
      </tr>
      <tr>
          <td>CA certificate roadmap</td>
          <td>Contact CA vendor for ML-DSA issuance timeline</td>
          <td>🟡 2026-2027</td>
      </tr>
      <tr>
          <td>JWT signing migration</td>
          <td>Implement ML-DSA-44 key provider</td>
          <td>🟡 2027</td>
      </tr>
      <tr>
          <td>SAML certificate upgrade</td>
          <td>Dual-key operation → PQC-only</td>
          <td>🟡 2027-2028</td>
      </tr>
      <tr>
          <td>Client library audit</td>
          <td>Verify JWT/SAML libs support ML-DSA (BouncyCastle 2.x, python-cryptography 43+)</td>
          <td>🟡 2027</td>
      </tr>
      <tr>
          <td>Vendor PQC roadmaps</td>
          <td>Contractually require PQC support dates from Auth0/Okta/Ping</td>
          <td>🟡 2026</td>
      </tr>
      <tr>
          <td>Documentation update</td>
          <td>Update key rotation runbooks for ML-DSA procedures</td>
          <td>🟢 2028</td>
      </tr>
      <tr>
          <td>PQC audit</td>
          <td>External validation of PQC implementation</td>
          <td>🟢 2029-2030</td>
      </tr>
  </tbody>
</table>
<h2 id="python-and-java-library-support">Python and Java Library Support</h2>
<p><strong>Python (cryptography ≥ 43.0):</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">from</span> cryptography.hazmat.primitives.asymmetric.ml_dsa <span style="color:#f92672">import</span> MLDSAPrivateKey, MLDSAPublicKey
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> cryptography.hazmat.primitives.asymmetric <span style="color:#f92672">import</span> ml_dsa
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Generate ML-DSA-44 signing key</span>
</span></span><span style="display:flex;"><span>private_key <span style="color:#f92672">=</span> ml_dsa<span style="color:#f92672">.</span>generate_private_key(ml_dsa<span style="color:#f92672">.</span>MLDSAParameterSet<span style="color:#f92672">.</span>ML_DSA_44)
</span></span><span style="display:flex;"><span>public_key <span style="color:#f92672">=</span> private_key<span style="color:#f92672">.</span>public_key()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Sign a JWT payload manually</span>
</span></span><span style="display:flex;"><span>message <span style="color:#f92672">=</span> <span style="color:#e6db74">b</span><span style="color:#e6db74">&#34;header.payload&#34;</span>
</span></span><span style="display:flex;"><span>signature <span style="color:#f92672">=</span> private_key<span style="color:#f92672">.</span>sign(message)
</span></span></code></pre></div><p><strong>Java (BouncyCastle 2.0+ FIPS):</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">import</span> org.bouncycastle.pqc.jcajce.spec.DilithiumParameterSpec;
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> java.security.KeyPairGenerator;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>KeyPairGenerator kpg <span style="color:#f92672">=</span> KeyPairGenerator.<span style="color:#a6e22e">getInstance</span>(<span style="color:#e6db74">&#34;ML-DSA&#34;</span>, <span style="color:#e6db74">&#34;BCFIPS&#34;</span>);
</span></span><span style="display:flex;"><span>kpg.<span style="color:#a6e22e">initialize</span>(DilithiumParameterSpec.<span style="color:#a6e22e">dilithium2</span>); <span style="color:#75715e">// ML-DSA-44 equivalent</span>
</span></span><span style="display:flex;"><span>KeyPair keyPair <span style="color:#f92672">=</span> kpg.<span style="color:#a6e22e">generateKeyPair</span>();
</span></span></code></pre></div><p><strong>Node.js:</strong> No native ML-DSA support yet in Node.js crypto. Use <code>@noble/post-quantum</code> (0.2+) for pure-JS ML-DSA implementation:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">import</span> { <span style="color:#a6e22e">ml_dsa44</span> } <span style="color:#a6e22e">from</span> <span style="color:#e6db74">&#39;@noble/post-quantum/ml-dsa&#39;</span>;
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> { <span style="color:#a6e22e">secretKey</span>, <span style="color:#a6e22e">publicKey</span> } <span style="color:#f92672">=</span> <span style="color:#a6e22e">ml_dsa44</span>.<span style="color:#a6e22e">keygen</span>();
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">signature</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">ml_dsa44</span>.<span style="color:#a6e22e">sign</span>(<span style="color:#a6e22e">secretKey</span>, <span style="color:#a6e22e">message</span>);
</span></span></code></pre></div><h2 id="cross-links-and-further-reading">Cross-Links and Further Reading</h2>
<p>For context on the broader identity security landscape, see our <a href="/posts/post-quantum-identity-and-access-management-for-ai-agents/">post-quantum IAM for AI agents</a> overview. For securing service-to-service OAuth flows (where PQC mTLS is most critical), see <a href="/posts/mtls-certificate-authentication-microservices-kubernetes/">mTLS Certificate Authentication for Microservices in Kubernetes</a>. For managing token lifecycle during the migration period, see <a href="/posts/oauth-21-security-best-practices-mandatory-pkce-and-token-binding/">OAuth 2.0 Security Best Practices</a>.</p>
<p>The 2030 deadline is 3.5 years away — enough time to plan, but not enough to delay starting. Begin with the TLS hybrid migration (Phase 1) this year: it&rsquo;s the highest-impact, lowest-disruption change and immediately protects against harvest-now-decrypt-later attacks.</p>
]]></content:encoded></item></channel></rss>