<?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>DEV Community: Autional</title>
    <description>The latest articles on DEV Community by Autional (@autional).</description>
    <link>https://dev.to/autional</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4172455%2F6a7ed542-7e52-4477-a6e1-21f0ccc3d88e.png</url>
      <title>DEV Community: Autional</title>
      <link>https://dev.to/autional</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/autional"/>
    <language>en</language>
    <item>
      <title>How JWT Signing Keys Are Issued and Rotated (and Why 'alg' Deserves Distrust)</title>
      <dc:creator>Autional</dc:creator>
      <pubDate>Fri, 09 Oct 2026 05:01:54 +0000</pubDate>
      <link>https://dev.to/autional/how-jwt-signing-keys-are-issued-and-rotated-and-why-alg-deserves-distrust-2126</link>
      <guid>https://dev.to/autional/how-jwt-signing-keys-are-issued-and-rotated-and-why-alg-deserves-distrust-2126</guid>
      <description>&lt;p&gt;Someone forwards a coupon that looks like it came from your store — same name, same styling. It’s fake. A JWT has the exact same problem: &lt;strong&gt;what makes it real is not what it says, but who could produce its signature.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A JWT is three parts
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;header.payload.signature&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The signature is computed over &lt;strong&gt;header + payload&lt;/strong&gt;. Change a single byte and it no longer matches — that’s the whole point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keys are a pair
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Private key&lt;/strong&gt; — used to &lt;em&gt;sign&lt;/em&gt;. There is exactly one, and it never leaves the issuer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public key&lt;/strong&gt; — used to &lt;em&gt;verify&lt;/em&gt;. It’s published, so anyone can check a signature.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So: only the issuer can &lt;em&gt;produce&lt;/em&gt; a signature, but everyone can &lt;em&gt;verify&lt;/em&gt; one. The public key can verify — it cannot forge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing keys: JWKS + &lt;code&gt;kid&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Verifiers fetch the public keys from a &lt;strong&gt;JWKS&lt;/strong&gt; endpoint (&lt;code&gt;/.well-known/jwks.json&lt;/code&gt;). Each key carries a &lt;strong&gt;&lt;code&gt;kid&lt;/code&gt;&lt;/strong&gt; (key id), and each issued token declares which &lt;code&gt;kid&lt;/code&gt; signed it. That’s how a verifier picks the right public key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rotation: overlap or you break everything
&lt;/h2&gt;

&lt;p&gt;When you rotate keys, &lt;strong&gt;publish the new public key first and keep the old one alongside&lt;/strong&gt; until every token signed by the old key has expired. Pull the old key too early and every live token becomes invalid at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify with a fixed algorithm — never trust the token
&lt;/h2&gt;

&lt;p&gt;Only accept signatures from an &lt;strong&gt;explicit algorithm allowlist&lt;/strong&gt; (e.g. RS256/ES256). Never trust the token’s own &lt;code&gt;alg&lt;/code&gt; header — this is the classic &lt;code&gt;alg=none&lt;/code&gt; and algorithm-confusion footgun. RFC 8725 (JWT Best Current Practices) is explicit about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real case: Storm-0558 (2023)
&lt;/h2&gt;

&lt;p&gt;In 2023, a signing key that should have been scoped to one system was obtained and used to &lt;strong&gt;forge tokens&lt;/strong&gt;, letting attackers read email across &lt;strong&gt;20+ organizations&lt;/strong&gt;. A single leaked signing key is a skeleton key for everything that trusts it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Engineering practice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Generate keys as a pair (RSA-2048 / EC). The &lt;strong&gt;private key never leaves the service&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Publish &lt;strong&gt;JWKS&lt;/strong&gt; with a &lt;code&gt;kid&lt;/code&gt; on each key; include the &lt;code&gt;kid&lt;/code&gt; in every token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rotate with overlap&lt;/strong&gt;: new + old public keys published together until old tokens expire.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix the algorithm whitelist&lt;/strong&gt;; reject &lt;code&gt;none&lt;/code&gt;; don’t let the token tell you how to verify it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These practices come from building &lt;strong&gt;Autional&lt;/strong&gt;, an open-core identity layer — &lt;a href="https://www.autional.com" rel="noopener noreferrer"&gt;https://www.autional.com&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reference: RFC 7515 (JWS), RFC 7517 (JWK/JWKS), RFC 7518 (JWA), RFC 7519 (JWT), RFC 8725 (JWT BCP); Storm-0558 (Microsoft disclosure 2023 / CISA CSRB report 2024).&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>authentication</category>
      <category>backend</category>
      <category>cybersecurity</category>
      <category>security</category>
    </item>
    <item>
      <title>Base64 Is Not Encryption: Encoding, Hashing, Encryption and Signing Are Four Different Tools</title>
      <dc:creator>Autional</dc:creator>
      <pubDate>Fri, 09 Oct 2026 04:54:52 +0000</pubDate>
      <link>https://dev.to/autional/base64-is-not-encryption-encoding-hashing-encryption-and-signing-are-four-different-tools-3o65</link>
      <guid>https://dev.to/autional/base64-is-not-encryption-encoding-hashing-encryption-and-signing-are-four-different-tools-3o65</guid>
      <description>&lt;p&gt;“I turned it into gibberish, so it’s encrypted now” — if that sounds familiar, it’s probably Base64. Anyone can reverse it, no key required. Encoding, hashing, encryption and signing are four different tools that get mixed up constantly. Use the wrong one and you leak.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four tools
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Encoding (Base64)&lt;/strong&gt; — change the representation so binary data can travel through text-only channels. Provides &lt;strong&gt;zero&lt;/strong&gt; secrecy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hashing (SHA-256, SM3)&lt;/strong&gt; — a one-way fingerprint. Verifies integrity and stores passwords. You can’t reverse it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption (AES-256-GCM, SM4-GCM)&lt;/strong&gt; — a lock. You need the key to read it back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signing (Ed25519, RSA)&lt;/strong&gt; — a seal. Proves &lt;em&gt;who&lt;/em&gt; sent it and that it wasn’t changed. Publicly verifiable, but not secret.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Two questions tell them apart
&lt;/h2&gt;

&lt;p&gt;Does it need a key? Can you reverse it?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Needs a key?&lt;/th&gt;
&lt;th&gt;Reversible?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Encoding&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (trivially)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hashing&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encryption&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (with the key)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signing&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Verifiable, not secret&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Use the wrong one and you leak
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Encoding as secrecy → Base64 reverses in one step.&lt;/li&gt;
&lt;li&gt;Hashing as signing → you can’t tell &lt;em&gt;who&lt;/em&gt; sent it.&lt;/li&gt;
&lt;li&gt;Encryption to store passwords → a key leak becomes plaintext.&lt;/li&gt;
&lt;li&gt;Signing as encryption → signatures don’t hide anything.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A real case: Heartbleed (CVE-2014-0160)
&lt;/h2&gt;

&lt;p&gt;In 2014, OpenSSL’s heartbeat lacked bounds checking, leaking up to 64 KB of process memory per request — potentially including private keys. Everything that relied on that key for secrecy or signing was compromised; encoding and hashing, which need no key, were unaffected. &lt;strong&gt;Encryption and signing both hang on the key.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Engineering practice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Base64 only for transport/display — never for secrecy.&lt;/li&gt;
&lt;li&gt;SHA-256 / HMAC-SHA256 / SM3 for integrity and password storage (with bcrypt/argon2 + salt).&lt;/li&gt;
&lt;li&gt;Only AEAD ciphers for encryption (AES-256-GCM / SM4-GCM).&lt;/li&gt;
&lt;li&gt;Ed25519 for signing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These practices come from building &lt;strong&gt;Autional&lt;/strong&gt;, an open-core identity layer — &lt;a href="https://www.autional.com" rel="noopener noreferrer"&gt;https://www.autional.com&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reference: RFC 4648 (Base64), FIPS 180-4 (SHA-2), FIPS 197 (AES) / NIST SP 800-38D (GCM), RFC 8032 (Ed25519); Heartbleed (CVE-2014-0160).&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
    </item>
    <item>
      <title>How Websites Store Your Password: Hashing Encryption (You Also Need Salt — and Slowness)</title>
      <dc:creator>Autional</dc:creator>
      <pubDate>Fri, 09 Oct 2026 04:32:18 +0000</pubDate>
      <link>https://dev.to/autional/how-websites-store-your-password-hashing-encryption-you-also-need-salt-and-slowness-42ic</link>
      <guid>https://dev.to/autional/how-websites-store-your-password-hashing-encryption-you-also-need-salt-and-slowness-42ic</guid>
      <description>&lt;p&gt;When your password shows up in a breach list, you might tell yourself: “the site encrypted my password, so it should be fine.” The truth is — the site shouldn’t &lt;em&gt;know&lt;/em&gt; your password, and doesn’t need to.&lt;/p&gt;

&lt;h2&gt;
  
  
  From plaintext to slow hashes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plaintext&lt;/strong&gt; — the password is stored as-is. RockYou (2009) leaked ~32 million plaintext passwords.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption&lt;/strong&gt; — lock it in a safe with a key. Problem: the safe &lt;em&gt;can be opened&lt;/em&gt;, the key lives on the same machine, and the same password produces the same ciphertext. Adobe (2013, 3DES-ECB) is the textbook case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hashing&lt;/strong&gt; — store only the “shredded” fingerprint; it can’t be reversed. Next login, shred again and compare.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast hashes aren’t enough&lt;/strong&gt; — precomputed dictionaries cover hundreds of millions of common passwords. LinkedIn (2012, unsalted SHA-1) had many passwords recovered within days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Salting&lt;/strong&gt; — a unique random salt per user, so the same password yields different hashes. The salt isn’t secret; reusing one salt for everyone is the real danger.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slow hashing (adaptive)&lt;/strong&gt; — deliberately slow: bcrypt / scrypt / Argon2, with a tunable cost that rises with hardware.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Three takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Hashing ≠ encryption (can’t reverse vs. can be unlocked);&lt;/li&gt;
&lt;li&gt;Always salt;&lt;/li&gt;
&lt;li&gt;Make it slow.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Engineering practice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use a standard slow hash: Argon2id (OWASP-recommended) / bcrypt / scrypt; PBKDF2 with high iterations.&lt;/li&gt;
&lt;li&gt;Salt ≥ 32 bits, tune cost upward over time (NIST SP 800-63B).&lt;/li&gt;
&lt;li&gt;Never write passwords to logs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These practices come from building &lt;strong&gt;Autional&lt;/strong&gt;, an open-core identity layer — &lt;a href="https://www.autional.com" rel="noopener noreferrer"&gt;https://www.autional.com&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reference: OWASP Password Storage Cheat Sheet, NIST SP 800-63B, RFC 9106 (Argon2), RFC 7914 (scrypt); cases: LinkedIn 2012, Adobe 2013, RockYou 2009.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>opensource</category>
    </item>
  </channel>
</rss>
