PageSourceSearch

https://falberthen.github.io/posts/jose101-pt1/

html falberthen.github.io collected 2026-10-03 09:10:53 UTC 48,851 bytes, 5 lines download raw bytes

1<!doctype html><html lang="en" ><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta name="theme-color" media="(prefers-color-scheme: light)" content="#f7f7f7"><meta name="theme-color" media="(prefers-color-scheme: dark)" content="#1b1b1e"><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"><meta name="viewport" content="width=device-width, user-scalable=no initial-scale=1, shrink-to-fit=no, viewport-fit=cover" ><meta name="generator" content="Jekyll v4.4.1" /><meta property="og:title" content="JOSE 101 [1/2]: A Practical Guide to JWT, JWA, JWS and JWE in .NET" /><meta property="og:locale" content="en" /><meta name="description" content="Felipe’s Dev Blog" /><meta name="twitter:description" property="og:description" content="Felipe’s Dev Blog" /><link rel="canonical" href="https://falberthen.github.io/posts/jose101-pt1/" /><meta property="og:url" content="https://falberthen.github.io/posts/jose101-pt1/" /><meta property="og:site_name" content="Felipe Henrique" /><meta property="og:type" content="article" /><meta property="article:published_time" content="2026-08-10T00:00:00-04:00" /><meta property="article:modified_time" content="2026-08-22T15:33:10-04:00" /><meta name="twitter:card" content="summary" /><meta name="twitter:title" content="JOSE 101 [1/2]: A Practical Guide to JWT, JWA, JWS and JWE in .NET" /><meta name="twitter:site" content="@" /> 
1<script type="application/ld+json"> {"@context":"https://schema.org","@type":"BlogPosting","dateModified":"2026-08-22T15:33:10-04:00","datePublished":"2026-08-10T00:00:00-04:00","description":"Felipe’s Dev Blog","headline":"JOSE 101 [1/2]: A Practical Guide to JWT, JWA, JWS and JWE in .NET","mainEntityOfPage":{"@type":"WebPage","@id":"https://falberthen.github.io/posts/jose101-pt1/"},"url":"https://falberthen.github.io/posts/jose101-pt1/"}</script>
1<title>JOSE 101 [1/2]: A Practical Guide to JWT, JWA, JWS and JWE in .NET | Felipe Henrique</title><link rel="icon" type="image/png" href="/assets/img/favicons/favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/svg+xml" href="/assets/img/favicons/favicon.svg"><link rel="shortcut icon" href="/assets/img/favicons/favicon.ico"><link rel="apple-touch-icon" sizes="180x180" href="/assets/img/favicons/apple-touch-icon.png"><link rel="manifest" href="/assets/img/favicons/site.webmanifest"><link rel="preconnect" href="https://fonts.googleapis.com" ><link rel="dns-prefetch" href="https://fonts.googleapis.com" ><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link rel="dns-prefetch" href="https://fonts.gstatic.com" ><link rel="preconnect" href="https://cdn.jsdelivr.net" ><link rel="dns-prefetch" href="https://cdn.jsdelivr.net" ><link rel="stylesheet" href="/assets/css/jekyll-theme-chirpy.css"><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Lato:wght@300;400&family=Source+Sans+Pro:wght@400;600;700;900&display=swap"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/css/all.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tocbot.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/loading-attribute-polyfill.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/glightbox.min.css"> 
1<script src="/assets/js/dist/theme.min.js"></script>
1 
1<script defer src="https://cdn.jsdelivr.net/combine/npm/[email protected]/dest/simple-jekyll-search.min.js,npm/[email protected]/dist/loading-attribute-polyfill.umd.min.js,npm/[email protected]/dist/js/glightbox.min.js,npm/[email protected]/dist/clipboard.min.js,npm/[email protected]/dayjs.min.js,npm/[email protected]/locale/en.js,npm/[email protected]/plugin/relativeTime.js,npm/[email protected]/plugin/localizedFormat.js,npm/[email protected]/dist/tocbot.min.js"></script>
1 
1<script defer src="/assets/js/dist/post.min.js"></script>
1 
1<script defer src="/app.min.js?baseurl=&register=true" ></script>
1<body><aside aria-label="Sidebar" id="sidebar" class="d-flex flex-column align-items-end"><header class="profile-wrapper"> <a href="/" id="avatar" class="rounded-circle"><img src="/assets/img/avatar.jpg" width="112" height="112" alt="avatar" onerror="this.style.display='none'"></a> <a class="site-title d-block" href="/">Felipe Henrique</a><p class="site-subtitle fst-italic mb-0">Technical Blog</p></header><nav class="flex-column flex-grow-1 w-100 ps-0"><ul class="nav"><li class="nav-item"> <a href="/" class="nav-link"> <i class="fa-fw fas fa-home"></i> <span>HOME</span> </a><li class="nav-item"> <a href="/categories/" class="nav-link"> <i class="fa-fw fas fa-stream"></i> <span>CATEGORIES</span> </a><li class="nav-item"> <a href="/tags/" class="nav-link"> <i class="fa-fw fas fa-tag"></i> <span>TAGS</span> </a><li class="nav-item"> <a href="/archives/" class="nav-link"> <i class="fa-fw fas fa-archive"></i> <span>ARCHIVES</span> </a><li class="nav-item"> <a href="/about/" class="nav-link"> <i class="fa-fw fas fa-info"></i> <span>
1ABOUT</span> </a></ul></nav><div class="sidebar-bottom d-flex flex-wrap align-items-center w-100"> <button type="button" class="btn btn-link nav-link" aria-label="Switch Mode" id="mode-toggle"> <i class="fas fa-adjust"></i> </button> <span class="icon-border"></span> <a href="https://github.com/falberthen" aria-label="github" target="_blank" rel="noopener noreferrer" > <i class="fab fa-github-alt"></i> </a> <a href="https://www.linkedin.com/in/felipe-alberto-hl" aria-label="linkedin" target="_blank" rel="noopener noreferrer" > <i class="fab fa-linkedin"></i> </a> <a href="javascript:location.href = 'mailto:' + ['fealberto','gmail.com'].join('@')" aria-label="email" > <i class="fas fa-envelope"></i> </a> <a href="/feed.xml" aria-label="rss" > <i class="fas fa-rss"></i> </a></div></aside><div id="main-wrapper" class="d-flex justify-content-center"><div class="container d-flex flex-column px-xxl-5"><header id="topbar-wrapper" class="flex-shrink-0" aria-label="Top Bar"><div id="topbar" class="d-flex align-items-center justify-content-between px-lg-3 h-100" ><nav id="breadcrumb" aria-label="Breadcrumb"> <span> <a href="/">Home</a> </span> <span>JOSE 101 [1/2]: A Practical Guide to JWT, JWA, JWS and JWE in .NET</span></nav><button type="button" id="sidebar-trigger" class="btn btn-link" aria-label="Sidebar"> <i class="fas fa-bars fa-fw"></i> </button><div id="topbar-title"> Post</div><button type="button" id="search-trigger" class="btn btn-link" aria-label="Search"> <i class="fas fa-search fa-fw"></i> </button> <search id="search" class="align-items-center ms-3 ms-lg-0"> <i class="fas fa-search fa-fw"></i> <input class="form-control" id="search-input" type="search" aria-label="search" autocomplete="off" placeholder="Search..." > </search> <button type="button" class="btn btn-link text-decoration-none" id="search-cancel">Cancel</button></div></header><div class="row flex-grow-1"><main aria-label="Main Content" class="col-12 col-lg-11 col-xl-9 px-md-4"><article class="px-1" data-toc="true"><header><h1 data-toc-skip>JOSE 101 [1/2]: A Practical Guide to JWT, JWA, JWS and JWE in .NET</h1><div class="post-meta text-muted"> <span> Posted <time data-ts="1786334400" data-df="ll" > Aug 10, 2026 </time> </span><div class="d-flex justify-content-between"> <span> By <em> <a href="https://github.com/falberthen">Felipe Henrique</a> </em> </span><div> <span class="readtime" data-bs-toggle="tooltip" data-bs-placement="bottom" title="2290 words" > <em>12 min</em> read</span></div></div></div></header><div id="toc-bar" class="d-flex align-items-center justify-content-between invisible"> <span class="label text-truncate">JOSE 101 [1/2]: A Practical Guide to JWT, JWA, JWS and JWE in .NET</span> <button type="button" class="toc-trigger btn me-1"> <i class="fa-solid fa-list-ul fa-fw"></i> </button></div><button id="toc-solo-trigger" type="button" class="toc-trigger btn btn-outline-secondary btn-sm"> <span class="label ps-2 pe-1">Contents</span> <i class="fa-solid fa-angle-right fa-fw"></i> </button> <dialog id="toc-popup" class="p-0"><div class="header d-flex flex-row align-items-center justify-content-between"><div class="label text-truncate py-2 ms-4">JOSE 101 [1/2]: A Practical Guide to JWT, JWA, JWS and JWE in .NET</div><button id="toc-popup-close" type="button" class="btn mx-1 my-1 opacity-75"> <i class="fas fa-close"></i> </button></div><div id="toc-popup-content" class="px-4 py-3 pb-4"></div></dialog><div class="content"><p><a href="https://raw.githubusercontent.com/falberthen/JOSE_101/master/docs/screenshots/menu.png" class="popup img-link shimmer"><img src="https://raw.githubusercontent.com/falberthen/JOSE_101/master/docs/screenshots/menu.png" loading="lazy"></a></p><p>Here we go again, this time on a topic that trips up even seasoned developers, hopefully making it simpler. While most articles I’ve seen on the internet stop at “sign a token with HS256 and move on”, I’m going further in this post with a more comprehensive guide to grasp all the important concepts, alongside the practical <a href="https://github.com/falberthen/JOSE_101" target="_blank">JOSE_101</a> <code class="language-plaintext highlighter-rouge">.NET playground app</code> you can use to test everything shown here.</p><p>The post covers signing tokens with symmetric and asymmetric keys, encrypting payloads to make them unreadable (not just signed), and combining both by nesting a signed token inside an encrypted one.</p><p>As you advance through the topics, complexity grows, and you’ll come away not just knowing what JWS and JWE stand for, but understanding which one to pick, based on your needs and the trade-offs involved.</p><p>⚠️ Disclaimer: This series and the app cover a curated set of algorithms picked to teach the concepts (<code class="language-plaintext highlighter-rouge">HS256</code>, <code class="language-plaintext highlighter-rouge">RS256</code>, <code class="language-plaintext highlighter-rouge">ES256</code> for signing; <code class="language-plaintext highlighter-rouge">dir</code> and <code class="language-plaintext highlighter-rouge">RSA-OAEP</code> for key management; <code class="language-plaintext highlighter-rouge">A256GCM</code> for content), not every JOSE variant available.</p><p>If you’re already well versed in the JWS concepts, you can jump straight to <a href="/posts/jose101-pt2/">JOSE 101 (2/2)</a>, where I finish the series with JWE.</p><p><br /></p><h2 id="the-j-squad"><span class="me-2">The J squad</span><a href="#the-j-squad" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h2><hr /><p>Before diving into <strong>JOSE</strong>, it’s worth starting with the format everything here is built on: <a href="https://en.wikipedia.org/wiki/JSON" target="_blank">JSON (JavaScript Object Notation)</a>, the default way systems exchange structured data, readable by humans, easy to parse, and supported natively or via libraries in effectively every language. It’s simple by design: just objects, arrays, strings, numbers, booleans, and null.</p><p>That simplicity is exactly why JOSE was built around it. When the industry needed a 
1standard way to <code class="language-plaintext highlighter-rouge">sign</code> and <code class="language-plaintext highlighter-rouge">encrypt</code> small chunks of data, such as <code class="language-plaintext highlighter-rouge">tokens</code>, <code class="language-plaintext highlighter-rouge">claims</code> and <code class="language-plaintext highlighter-rouge">credentials</code>, JSON fit because it carries enough structure to be meaningful, while staying simple enough to serialize compactly and parse anywhere.</p><p>Every concept in this post is a JSON object with rules attached, determining what a token contains, which algorithms are allowed to protect it, and how signing or encryption is applied on top.</p><h3 id="jose-json-object-signing-and-encryption"><span class="me-2">JOSE (JSON Object Signing and Encryption)</span><a href="#jose-json-object-signing-and-encryption" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h3><p>JOSE isn’t an implementation, but a specification, more precisely, a family of <code class="language-plaintext highlighter-rouge">RFCs</code> (Request for Comments) that define exactly how those “rules attached to a JSON object” work. It’s not about what your data should be, but how to protect it.</p><p>Since it’s platform-agnostic, there are plenty of implementations across multiple stacks and languages. In this post, I’ll stick to <a href="https://github.com/dvsekhvalnov/jose-jwt" target="_blank">jose-jwt</a>, a popular .NET implementation I used in the console app.</p><h3 id="jwt-json-web-token"><span class="me-2">JWT (JSON Web Token)</span><a href="#jwt-json-web-token" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h3><p>JWT is the format most people refer to as ‘token’, usually in the authentication context, largely used in APIs and distributed systems. It’s a compact, URL-safe way to represent a set of claims, but on its own, it says nothing about data protection, and it’s where the other Js below come in.</p><p>Technically, a JOSE token is built from two JSON objects. The <code class="language-plaintext highlighter-rouge">header</code> describes how the token is protected, where <code class="language-plaintext highlighter-rouge">alg</code> defines the algorithm used, and <code class="language-plaintext highlighter-rouge">typ</code> its media type:</p><div class="language-json highlighter-rouge"><div class="code-header"> <span data-label-text="JSON"><i class="fas fa-code fa-fw small"></i></span> <button aria-label="copy" data-title-succeed="Copied!"><i class="far fa-clipboard"></i></button></div><div class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2</pre><td class="rouge-code"><pre><span class="p">{</span><span class="w"> </span><span class="nl">"alg"</span><span class="p">:</span><span class="w"> </span><span class="s2">"HS256"</span><span class="p">,</span><span class="w"> </span><span class="nl">"typ"</span><span class="p">:</span><span class="w"> </span><span class="s2">"JWT"</span><span class="w"> </span><span class="p">}</span><span class="w">
3</span></pre></table></code></div></div><p>And the <code class="language-plaintext highlighter-rouge">payload</code> carries the claims, the actual data you want to transport:</p>
3<script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Ffalberthen%2FJOSE_101%2Fblob%2Fmaster%2Fsamples%2Fpayloads%2Fclaims-basic.json&amp;style=vs2015&amp;showFileMeta=on&amp;showCopy=on"></script>
3<p>Both get <em>base64url-encoded</em> and <strong>joined with dots</strong> into a long string. How many parts come after those two is what tells whether it’s a <code class="language-plaintext highlighter-rouge">JWS</code> or a <code class="language-plaintext highlighter-rouge">JWE</code>.</p><p>⚠️ <em>Note: the header isn’t something you usually write by hand. The library builds it for you at signing time, filling <code class="language-plaintext highlighter-rouge">alg</code> with whichever algorithm you asked for and <code class="language-plaintext highlighter-rouge">typ</code> with <code class="language-plaintext highlighter-rouge">JWT</code>. All you hand it is the payload.</em></p><h3 id="jwa-json-web-algorithms"><span class="me-2">JWA (JSON Web Algorithms)</span><a href="#jwa-json-web-algorithms" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h3><p>JWA is the registry of algorithm identifiers JOSE tokens are allowed to use, and it covers two different jobs.</p><ul><li><strong>For signing</strong>, there’s a single choice: the <code class="language-plaintext highlighter-rouge">alg</code> header names the signing algorithm (e.g., <code class="language-plaintext highlighter-rouge">HS256</code>, <code class="language-plaintext highlighter-rouge">RS256</code>, <code class="language-plaintext highlighter-rouge">ES256</code>, etc).<li><strong>For encryption</strong>, there are two: <code class="language-plaintext highlighter-rouge">alg</code> names the <em>key management</em> algorithm (e.g., <code class="language-plaintext highlighter-rouge">dir</code>, <code class="language-plaintext highlighter-rouge">RSA-OAEP</code>, etc), and <code class="language-plaintext highlighter-rouge">enc</code> names the <em>content encryption</em> algorithm (e.g., <code class="language-plaintext highlighter-rouge">A256GCM</code>, etc).</ul><p>⚠️ <em>Note: You can assign the <code class="language-plaintext highlighter-rouge">alg</code> as <code class="language-plaintext highlighter-rouge">none</code> if you really don’t need to sign the token, but keep in mind it adds a security risk if a system relies on signature verification.</em></p><h3 id="jwkjwks-json-web-key"><span class="me-2">JWK/JWKS (JSON Web Key)</span><a href="#jwkjwks-json-web-key" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h3><p>JWK defines how to represent cryptographic keys as JSON objects, for key distribution. A <strong>JWKS</strong> (JSON Web Key Set) is simply an array of JWKs, typically published at an endpoint so verifiers can fetch the right public key on the fly. It’s covered by its own <a href="https://datatracker.ietf.org/doc/html/rfc7517" target="_blank">RFC 7517</a>, but falls outside the scope of this post.</p><h3 id="jws-json-web-signature"><span class="me-2">JWS (JSON Web Signature)</span><a href="#jws-json-web-signature" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h3><p>JWS is what a signed JWT looks like. The <code class="language-plaintext highlighter-rouge">payload</code> stays fully readable, <em>base64url-encoded but not encrypted</em>, and a signature proves it hasn’t been tampered with. It only lets you verify who signed it and that it wasn’t altered, but anyone can read it. In practice, when you use JWTs for production-grade applications, you’re (hopefully) using a JWS, because you must prove authenticity.</p><h3 id="jwe-json-web-encryption"><span class="me-2">JWE (JSON Web Encryption)</span><a href="#jwe-json-web-encryption" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h3><p>JWE is an encrypted JWT. The <code class="language-plaintext highlighter-rouge">payload</code> becomes <em>opaque ciphertext</em>, unreadable without the right key. <em>It guarantees that only the intended recipient can read it</em>, since the content is hidden from anyone else. While JWS only proves authenticity, <em>JWE hides content</em>.</p><p><br /></p><h2 id="jws---signing-algorithms-hmac-vs-rsa-vs-ecdsa"><span class="me-2">JWS - Signing algorithms: HMAC vs RSA vs ECDSA</span><a href="#jws---signing-algorithms-hmac-vs-rsa-vs-ecdsa" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h2><hr /><h3 id="symmetric-or-asymmetric"><span class="me-2">Symmetric or Asymmetric?</span><a href="#symmetric-or-asymmetric" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h3><p>Before signing anything, you need to pick an algorithm, and that choice comes down to one key question: <strong>do the signer and the verifier trust each other with the <em>same secret</em>, or not?</strong></p><p>That’s the split between <code class="language-plaintext highlighter-rouge">symmetric</code> and <code class="language-plaintext highlighter-rouge">asymmetric</code> algorithms, and it changes the whole trust model around the key, not just the math behind it.</p><p>A <code class="language-plaintext highlighter-rouge">symmetric</code> algorithm uses a <code class="language-plaintext highlighter-rouge">shared secret</code> for both signing and verifying: whoever holds it can produce a valid signature and check one. That’s simple and fast, but it also means every verifier is a <em>potential signer</em>, which implies both parties holding that secret must trust each other.</p><p>An <code class="language-plaintext highlighter-rouge">asymmetric</code> algorithm splits that power in two: a <code class="language-plaintext highlighter-rouge">private key</code> signs, a <code class="language-plaintext highlighter-rouge">public key</code> verifies. In practice, <em>
3anyone can check a signature’s authenticity</em> without ever being able to forge one, and that’s exactly what you want when tokens travel to services you don’t fully trust with signing power.</p><h3 id="the-three-segments"><span class="me-2">The three segments</span><a href="#the-three-segments" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h3><p>A JWS has three parts, joined by dots: <code class="language-plaintext highlighter-rouge">header</code><strong>.</strong><code class="language-plaintext highlighter-rouge">payload</code><strong>.</strong><code class="language-plaintext highlighter-rouge">signature</code>.</p><ul><li>The <code class="language-plaintext highlighter-rouge">header</code> declares the <code class="language-plaintext highlighter-rouge">alg</code>.<li>The <code class="language-plaintext highlighter-rouge">payload</code> carries the claims.<li>The <code class="language-plaintext highlighter-rouge">signature</code> is what proves the other two weren’t touched on the way.</ul><p>Let’s play with a variety of tokens using the app.</p><p>First, clone <a href="https://github.com/falberthen/JOSE_101" target="_blank">JOSE_101</a>, run it and choose this menu option: <strong>Verify / Decrypt (validate a token)</strong>.</p><div style="text-align:center"><a href="/assets/img/posts/2026-08-10-jose101/jws-menu-verify.png" class="popup img-link shimmer"><img src="/assets/img/posts/2026-08-10-jose101/jws-menu-verify.png" loading="lazy"></a></div><p>Then paste the token and the secret key to verify it. You can repeat the same process for all tokens below, while choosing the right menu option for each. <a href="https://raw.githubusercontent.com/falberthen/JOSE_101/master/docs/screenshots/sample1.png" class="popup img-link shimmer"><img src="https://raw.githubusercontent.com/falberthen/JOSE_101/master/docs/screenshots/sample1.png" loading="lazy"></a></p><p>This will allow us to decompose the token into segments, and validate its integrity. That’s the distinction the whole post rests on: <strong>signing protects those bytes, it never hides them</strong>.</p><p>⚠️ <em>Keys are published in the repo so anyone can reproduce the examples. Never reuse them to protect anything real!</em></p><h3 id="hmac-hs256---symmetric"><span class="me-2">HMAC (HS256) - Symmetric</span><a href="#hmac-hs256---symmetric" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h3><p><a href="https://en.wikipedia.org/wiki/HMAC" target="_blank">HMAC</a> <em>(Hash-based Message Authentication Code)</em> mixes a <code class="language-plaintext highlighter-rouge">secret key</code> with a <code class="language-plaintext highlighter-rouge">hash function</code>, a one-way algorithm that turns any input into a fixed-size fingerprint, so the same input always produces the same fingerprint, but you can’t work backwards from the fingerprint to the input. That combination produces a code that proves both integrity (nothing changed) and authenticity (only someone holding the secret could have produced it).</p><p><code class="language-plaintext highlighter-rouge">HMAC-SHA256</code> <strong>pairs</strong> <code class="language-plaintext highlighter-rouge">HMAC</code> with <a href="https://en.wikipedia.org/wiki/SHA-2" target="_blank">
3SHA-256</a> <em>(Secure Hash Algorithm 2)</em>, a hash function whose fingerprint is <em>always 256 bits long</em>, no matter the size of the input. Together they give the <code class="language-plaintext highlighter-rouge">alg</code> value you’ll see in the token header: <code class="language-plaintext highlighter-rouge">HS256</code>.</p><p><strong>When to use it:</strong> whenever signer and verifier are the same system, or two systems that already trust each other with the same secret. Think a single backend signing its own session tokens, or a CI pipeline signing build artifacts that only its own deploy step needs to verify.</p><p><strong>Trade-off:</strong> it can’t prove <em>who</em> signed a token to a third party, and that means <strong>anyone holding the secret could have produced it</strong>. If that secret ever leaks, forged tokens become indistinguishable from real ones.</p><p><strong>Token example:</strong> 
3<script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Ffalberthen%2FJOSE_101%2Fblob%2Fmaster%2Fsamples%2Fjws-hmac.jwt&amp;style=vs2015&amp;showFileMeta=on&amp;showCopy=on"></script>
3</p><p><strong>Signature secret key:</strong> 
3<script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Ffalberthen%2FJOSE_101%2Fblob%2Fmaster%2Fkeys%2Fhmac-secret.txt&amp;style=vs2015&amp;showFileMeta=on&amp;showCopy=on"></script>
3</p><p><strong>Implementation:</strong> 
3<script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Ffalberthen%2FJOSE_101%2Fblob%2Fmaster%2Fsrc%2FJOSE_101.Core%2FJws%2FJwsHmacFactory.cs&amp;style=vs2015&amp;showFileMeta=on&amp;showCopy=on"></script>
3</p><h3 id="rsa-rs256---asymmetric"><span class="me-2">RSA (RS256) - Asymmetric</span><a href="#rsa-rs256---asymmetric" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h3><p><a href="https://en.wikipedia.org/wiki/RSA_cryptosystem" target="_blank">RSA</a>, named after its inventors <code class="language-plaintext highlighter-rouge">Rivest</code>, <code class="language-plaintext highlighter-rouge">Shamir</code> and <code class="language-plaintext highlighter-rouge">Adleman</code>, is an asymmetric algorithm whose security relies on <strong>how hard it is to factor the product of two large prime numbers</strong>. That combination lets the <code class="language-plaintext highlighter-rouge">private key</code> sign while the <code class="language-plaintext highlighter-rouge">public key</code> verifies, so proving a signature never requires the power to produce one.</p><p><code class="language-plaintext highlighter-rouge">RSASSA-PKCS1-v1_5</code> <strong>pairs</strong> <code class="language-plaintext highlighter-rouge">RSA</code> with <code class="language-plaintext highlighter-rouge">SHA-256</code> for hashing. Together they give the <code class="language-plaintext highlighter-rouge">alg</code> value you’ll see in the token header: <code class="language-plaintext highlighter-rouge">RS256</code>.</p><p><strong>When to use it:</strong> unlike <code class="language-plaintext highlighter-rouge">HS256</code> above, it fits scenarios where <strong>the verifier shouldn’t be able to forge tokens</strong>. Think a token handed to multiple downstream services, or a public key published as a <a href="https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-key-sets" target="_blank">JWKS endpoint</a>.</p><p><strong>Trade-off:</strong> <em>it costs more CPU than HMAC</em> and needs <code class="language-plaintext highlighter-rouge">key-pair management</code>, <code class="language-plaintext highlighter-rouge">rotation</code>, <code class="language-plaintext highlighter-rouge">distribution</code> of the public key. That adds complexity and governance, but it’s the price for scaling verification out to parties you don’t fully trust with signing power. It also produces the largest signature of the three (four times ECDSA’s), which rides on every request.</p><p>💡 One detail worth knowing before you commit to it: <code class="language-plaintext highlighter-rouge">PKCS#1 v1.5</code> is the older of the two padding schemes RSA signatures can use. It’s still everywhere and still considered safe for signing, but the modern choice is <code class="language-plaintext highlighter-rouge">RSA-PSS</code>, which adds randomness to the padding and appears in JOSE as <code class="language-plaintext highlighter-rouge">PS256</code>. If you’re picking RSA for a new system and both ends support it, prefer <code class="language-plaintext highlighter-rouge">PS256</code>.</p><p><strong>Token example:</strong> 
3<script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Ffalberthen%2FJOSE_101%2Fblob%2Fmaster%2Fsamples%2Fjws-rsa.jwt&amp;style=vs2015&amp;showFileMeta=on&amp;showCopy=on"></script>
3</p><p><strong>RSA Public key:</strong> 
3<script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Ffalberthen%2FJOSE_101%2Fblob%2Fmaster%2Fkeys%2Frsa-public.pem&amp;style=vs2015&amp;showFileMeta=on&amp;showCopy=on"></script>
3</p><p><strong>Implementation:</strong> 
3<script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Ffalberthen%2FJOSE_101%2Fblob%2Fmaster%2Fsrc%2FJOSE_101.Core%2FJws%2FJwsRsaFactory.cs&amp;style=vs2015&amp;showFileMeta=on&amp;showCopy=on"></script>
3</p><h3 id="ecdsa-es256---asymmetric"><span class="me-2">ECDSA (ES256) - Asymmetric</span><a href="#ecdsa-es256---asymmetric" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h3><p><a href="https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm" target="_blank">ECDSA</a> <em>(Elliptic Curve Digital Signature Algorithm)</em> is also asymmetric, but its security comes from the <strong>math of elliptic curves instead of factoring large numbers</strong>, which is what lets it reach the same security level as RSA with much smaller keys and signatures, and cheaper signing.</p><p><code class="language-plaintext highlighter-rouge">ECDSA</code> <strong>pairs</strong> the <a href="https://std.neuromancer.sk/nist/P-256" target="_blank">P-256</a> curve with <code class="language-plaintext highlighter-rouge">SHA-256</code> for hashing. Together they give the <code class="language-plaintext highlighter-rouge">alg</code> value you’ll see in the token header: <code class="language-plaintext highlighter-rouge">ES256</code>.</p><p><strong>When to use it:</strong> it fits the same scenarios as <code class="language-plaintext highlighter-rouge">RS256</code>, but pays less for them. Think a high-traffic API where every request carries a token, or mobile and embedded clients where both bandwidth and CPU are scarce.</p><p><strong>Trade-off:</strong> every signature needs a high-quality random nonce. Reuse one and you leak the private key, a concern RSA doesn’t have. Verification is also slower than RS256.</p><p>⚠️ <em>That’s not a theoretical risk: Sony shipped the PlayStation 3 signing with the same nonce every single time, and some smart folks used exactly that to recover the console’s private signing key. In .NET the nonce is generated for you, so it’s not something you handle in application code.</em> Check <a href="https://deeprnd.medium.com/decoding-the-playstation-3-hack-unraveling-the-ecdsa-random-generator-flaw-e9074a51b831" target="_blank">this awesome</a> blog article for more details.</p><p>💡 <em>Although ECDSA yields smaller tokens and cheaper signing at comparable security, most identity providers (Auth0, Okta, Azure AD, Duende IdentityServer) default to RS256, which OpenID Connect requires every provider to support.</em></p><p><strong>Token example:</strong> 
3<script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Ffalberthen%2FJOSE_101%2Fblob%2Fmaster%2Fsamples%2Fjws-ecdsa.jwt&amp;style=vs2015&amp;showFileMeta=on&amp;showCopy=on"></script>
3</p><p><strong>EC Public key:</strong> 
3<script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Ffalberthen%2FJOSE_101%2Fblob%2Fmaster%2Fkeys%2Fec-public.pem&amp;style=vs2015&amp;showFileMeta=on&amp;showCopy=on"></script>
3</p><p><strong>Implementation:</strong> 
3<script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Ffalberthen%2FJOSE_101%2Fblob%2Fmaster%2Fsrc%2FJOSE_101.Core%2FJws%2FJwsEcdsaFactory.cs&amp;style=vs2015&amp;showFileMeta=on&amp;showCopy=on"></script>
3</p><h3 id="same-claims-three-signatures"><span class="me-2">Same claims, three signatures</span><a href="#same-claims-three-signatures" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h3><p>Since the first two segments are the same length across all three (the <code class="language-plaintext highlighter-rouge">alg</code> value differs but is always five characters), every size difference you can see comes from the signature alone. The table makes the trade-off easy to spot:</p><div class="table-wrapper"><table><thead><tr><th><code class="language-plaintext highlighter-rouge">alg</code><th>Signature<th>Token<th>Key used<tbody><tr><td><code class="language-plaintext highlighter-rouge">HS256</code><td>43 chars<td>121 chars<td>one shared 256-bit secret<tr><td><code class="language-plaintext highlighter-rouge">ES256</code><td>86 chars<td>164 chars<td>EC <code class="language-plaintext highlighter-rouge">P-256</code> key pair<tr><td><code class="language-plaintext highlighter-rouge">RS256</code><td>342 chars<td>420 chars<td>RSA <code class="language-plaintext highlighter-rouge">2048</code> key pair</table></div><p>Notice that <code class="language-plaintext highlighter-rouge">RS256</code> produces a signature four times larger than <code class="language-plaintext highlighter-rouge">ES256</code> at a comparable security level, and that cost rides along on every single request carrying the token. And the payload sits there in plain sight in all three, base64url-encoded and easily readable. Signing never hides anything, and that’s precisely the gap <code class="language-plaintext highlighter-rouge">JWE</code> exists to fill.</p><p>💡 <em>Rule of thumb:</em></p><ul><li>Use <code class="language-plaintext highlighter-rouge">HMAC</code> when signer and verifier are the same trusted system.<li>Use <code class="language-plaintext highlighter-rouge">RSA</code> or <code class="language-plaintext highlighter-rouge">ECDSA</code> when they’re not, preferring <code class="language-plaintext highlighter-rouge">ECDSA</code> for smaller tokens, or <code class="language-plaintext highlighter-rouge">RSA</code> when verification throughput or ecosystem compatibility weighs more.</ul><p><br /></p><h2 id="️-algorithm-pinning-one-rule-that-outranks-the-algorithm-choice"><span class="me-2">⚠️ Algorithm pinning: One rule that outranks the algorithm choice</span><a href="#️-algorithm-pinning-one-rule-that-outranks-the-algorithm-choice" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h2><hr /><p>Whichever you pick, the verifier must be told which algorithm to expect, never trusting the token’s own <code class="language-plaintext highlighter-rouge">alg</code> field, because the header is potentially attacker-controlled until the signature is checked, and taking it at face value is the root of the two classic JWT attacks:</p><ul><li><code class="language-plaintext highlighter-rouge">alg: none</code>, where an unsigned token gets accepted anyway.<li><code class="language-plaintext highlighter-rouge">RS256</code> to <code class="language-plaintext highlighter-rouge">HS256</code> confusion, where an attacker re-signs a token using your <em>public</em> key as if it were an HMAC secret.</ul><p>So declare the expected algorithm at the verification call, and a token that arrives with any other one gets <em>rejected before any key is touched</em>.</p><p>💡 Tip: With <code class="language-plaintext highlighter-rouge">jose-jwt</code>, use the <code class="language-plaintext highlighter-rouge">Verify()</code> method instead of <code class="language-plaintext highlighter-rouge">Decode()</code>. Verify will ensure the right algorithm was set, and throw an <code class="language-plaintext highlighter-rouge">InvalidAlgorithmException</code> if it can’t assert the signing algorithm type.</p><div class="language-csharp highlighter-rouge"><div class="code-header"> <span data-label-text="C#"><i class="fas fa-code fa-fw small"></i></span> <button aria-label="copy" data-title-succeed="Copied!"><i class="far fa-clipboard"></i></button></div><div class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
4</pre><td class="rouge-code"><pre><span class="n">JWT</span><span class="p">.</span><span class="nf">Verify</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="n">publicKey</span><span class="p">,</span> <span class="n">JwsAlgorithm</span><span class="p">.</span><span class="n">RS256</span><span class="p">);</span>  
5</pre></table></code></div></div><p><br /></p><h2 id="final-thoughts"><span class="me-2">Final thoughts</span><a href="#final-thoughts" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h2><hr /><p>In this post, I walked you through JWS concepts and the practical implementation in .NET, a quick tour of the theory, enough to reason about these decisions in real projects.</p><p>Choosing the right implementation is not only a technical decision but, more importantly, a business one, and it demands weighing the trade-offs.</p><p>With JWS covered, we’re ready to explore JWE in the <a href="/posts/jose101-pt2/">next post</a>. See you there!</p><hr /><p><br /></p><p><a href="https://github.com/falberthen/JOSE_101" target="_blank">Check the project on GitHub</a> <br /><br /></p><h2 id="links-worth-checking"><span class="me-2">Links worth checking</span><a href="#links-worth-checking" class="anchor text-muted"><i class="fas fa-hashtag"></i></a></h2><hr /><ul><li><a href="https://datatracker.ietf.org/doc/html/rfc7515" target="_blank">RFC 7515 - JSON Web Signature (JWS)</a><li><a href="https://datatracker.ietf.org/doc/html/rfc7516" target="_blank">RFC 7516 - JSON Web Encryption (JWE)</a><li><a href="https://datatracker.ietf.org/doc/html/rfc7517" target="_blank">
5RFC 7517 - JSON Web Key (JWK)</a><li><a href="https://datatracker.ietf.org/doc/html/rfc7518" target="_blank">RFC 7518 - JSON Web Algorithms (JWA)</a><li><a href="https://datatracker.ietf.org/doc/html/rfc7519" target="_blank">RFC 7519 - JSON Web Token (JWT)</a><li><a href="https://www.jwt.io/" target="_blank">jwt.io - decode and inspect tokens in the browser</a><li><a href="https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-key-sets" target="_blank">JWKS - publishing public keys for verification</a><li><a href="https://github.com/dvsekhvalnov/jose-jwt" target="_blank">jose-jwt</a><li><a href="https://deeprnd.medium.com/decoding-the-playstation-3-hack-unraveling-the-ecdsa-random-generator-flaw-e9074a51b831" target="_blank">Decoding the PlayStation 3 Hack: Unraveling the ECDSA Random Generator Flaw</a></ul><hr /> 
5<script src="https://giscus.app/client.js" data-repo="falberthen/blog_discussions" data-repo-id="MDEwOlJlcG9zaXRvcnk0MDU2ODQyNTg=" data-category="General" data-category-id="DIC_kwDOGC5AIs4B_Bug" data-mapping="pathname" data-reactions-enabled="1" data-emit-metadata="0" data-theme="transparent_dark" crossorigin="anonymous" async=""> </script>
5</div><div class="post-tail-wrapper text-muted"><div class="post-meta mb-3"> <i class="far fa-folder-open fa-fw me-1"></i> <a href="/categories/security/">Security</a>, <a href="/categories/cryptography/">Cryptography</a>, <a href="/categories/dotnet/">DotNet</a></div><div class="post-tags"> <i class="fa fa-tags fa-fw me-1"></i> <a href="/tags/jose/" class="post-tag no-text-decoration" >JOSE</a> <a href="/tags/jwt/" class="post-tag no-text-decoration" >JWT</a> <a href="/tags/jwa/" class="post-tag no-text-decoration" >JWA</a> <a href="/tags/jwk/" class="post-tag no-text-decoration" >JWK</a> <a href="/tags/jws/" class="post-tag no-text-decoration" >JWS</a> <a href="/tags/jwe/" class="post-tag no-text-decoration" >JWE</a> <a href="/tags/hmac/" class="post-tag no-text-decoration" >HMAC</a> <a href="/tags/rsa/" class="post-tag no-text-decoration" >RSA</a> <a href="/tags/ecdsa/" class="post-tag no-text-decoration" >ECDSA</a></div><div class=" post-tail-bottom d-flex justify-content-between align-items-center mt-5 pb-2 " ><div class="license-wrapper"> This post is licensed under <a href="https://creativecommons.org/licenses/by/4.0/"> CC BY 4.0 </a> by the author.</div><div class="share-wrapper d-flex align-items-center"> <span class="share-label text-muted">Share</span> <span class="share-icons"> <a href="https://twitter.com/intent/tweet?text=JOSE%20101%20[1/2]:%20A%20Practical%20Guide%20to%20JWT,%20JWA,%20JWS%20and%20JWE%20in%20.NET%20-%20Felipe%20Henrique&url=https%3A%2F%2Ffalberthen.github.io%2Fposts%2Fjose101-pt1%2F" target="_blank" rel="noopener" data-bs-toggle="tooltip" data-bs-placement="top" title="Twitter" aria-label="Twitter"> <i class="fa-fw fab fa-twitter"></i> </a> <a href="https://www.facebook.com/sharer/sharer.php?title=JOSE%20101%20[1/2]:%20A%20Practical%20Guide%20to%20JWT,%20JWA,%20JWS%20and%20JWE%20in%20.NET%20-%20Felipe%20Henrique&u=https%3A%2F%2Ffalberthen.github.io%2Fposts%2Fjose101-pt1%2F" target="_blank" rel="noopener" data-bs-toggle="tooltip" data-bs-placement="top" title="Facebook" aria-label="Facebook"> <i class="fa-fw fab fa-facebook-square"></i> </a> <a href="https://t.me/share/url?url=https%3A%2F%2Ffalberthen.github.io%2Fposts%2Fjose101-pt1%2F&text=JOSE%20101%20[1/2]:%20A%20Practical%20Guide%20to%20JWT,%20JWA,%20JWS%20and%20JWE%20in%20.NET%20-%20Felipe%20Henrique" target="_blank" rel="noopener" data-bs-toggle="tooltip" data-bs-placement="top" title="Telegram" aria-label="Telegram"> <i class="fa-fw fab fa-telegram"></i> </a> <button id="copy-link" aria-label="Copy link" class="btn small" data-bs-toggle="tooltip" data-bs-placement="top" title="Copy link" data-title-succeed="Link copied successfully!" > <i class="fa-fw fas fa-link pe-none fs-6"></i> </button> </span></div></div></div></article></main><aside aria-label="Panel" id="panel-wrapper" class="col-xl-3 ps-2 text-muted"><div class="access"><section id="access-lastmod"><h2 class="panel-heading">Recently Updated</h2><ul class="content list-unstyled ps-0 pb-1 ms-1 mt-2"><li class="text-truncate lh-lg"> <a href="/posts/ecommerceddd-pt5/">Hands-on DDD and Event Sourcing [5/6]: Wrapping up backend infrastructure</a><li class="text-truncate lh-lg"> <a href="/posts/ecommerceddd-pt6/">Hands-on DDD and Event Sourcing [6/6]: Angular SPA and API consumption</a><li class="text-truncate lh-lg"> <a href="/posts/ecommerceddd-pt1/">Hands-on DDD and Event Sourcing [1/6]: EcommerceDDD overview</a><li class="text-truncate lh-lg"> <a href="/posts/ecommerceddd-pt2/">Hands-on DDD and Event Sourcing [2/6]: Strategic and Tactical Design</a><li class="text-truncate lh-lg"> <a href="/posts/ecommerceddd-pt3/">Hands-on DDD and Event Sourcing [3/6]: Domain events, Event Sourcing and CQRS</a></ul></section><section><h2 class="panel-heading">Trending Tags</h2><div class="d-flex flex-wrap mt-3 mb-1 me-3"> <a class="post-tag btn btn-outline-primary" href="/tags/net6/">.NET6</a> <a class="post-tag btn btn-outline-primary" href="/tags/c-10/">C#10</a> <a class="post-tag btn btn-outline-primary" href="/tags/domain-driven-design/">Domain-driven Design</a> <a class="post-tag btn btn-outline-primary" href="/tags/eventsourcing/">EventSourcing</a> <a class="post-tag btn btn-outline-primary" href="/tags/microservices/">Microservices</a> <a class="post-tag btn btn-outline-primary" href="/tags/cqrs/">CQRS</a> <a class="post-tag btn btn-outline-primary" href="/tags/ienumerable/">IEnumerable</a> <a class="post-tag btn btn-outline-primary" href="/tags/linq/">Linq</a> <a class="post-tag btn btn-outline-primary" href="/tags/net7/">.NET7</a> <a class="post-tag btn btn-outline-primary" href="/tags/asp-net-core/">ASP.NET Core</a></div></section></div><div class="toc-border-cover z-3"></div><section id="toc-wrapper" class="invisible position-sticky ps-0 pe-4 pb-4"><h2 class="panel-heading ps-3 pb-2 mb-0">Contents</h2><nav id="toc"></nav></section></aside></div><div class="row"><div id="tail-wrapper" class="col-12 col-lg-11 col-xl-9 px-md-4"><aside id="related-posts" aria-labelledby="related-label"><h3 class="mb-4" id="related-label">Further Reading</h3><nav class="row row-cols-1 row-cols-md-2 row-cols-xl-3 g-4 mb-4"><article class="col"> <a href="/posts/jose101-pt2/" class="post-preview card h-100"><div class="card-body"> <time data-ts="1786766400" data-df="ll" > Aug 15, 2026 </time><h4 class="pt-0 my-2">JOSE 101 [2/2]: A Practical Guide to JWT, JWA, JWS and JWE in .NET</h4><div class="text-muted"><p>In the previous post, I covered JWS with some tokens and implementation samples. Now I’ll walk 
5you through JWE in the same way. JWE - Encryption algorithms: dir vs RSA-OAEP Two choices, not one ...</p></div></div></a></article></nav></aside><nav class="post-navigation d-flex justify-content-between" aria-label="Post Navigation"> <a href="/posts/api-clients/" class="btn btn-outline-primary" aria-label="Older" ><p>EcommerceDDD++: Streamlining API Client Generation with Kiota and Koalesce</p></a> <a href="/posts/jose101-pt2/" class="btn btn-outline-primary" aria-label="Newer" ><p>JOSE 101 [2/2]: A Practical Guide to JWT, JWA, JWS and JWE in .NET</p></a></nav><footer aria-label="Site Info" class=" d-flex flex-column justify-content-center text-muted flex-lg-row justify-content-lg-between align-items-lg-center pb-lg-3 " ><p>© <time>2026</time> <a href="https://github.com/falberthen">Felipe Henrique</a>. <span data-bs-toggle="tooltip" data-bs-placement="top" title="Except where otherwise noted, the blog posts on this site are licensed under the Creative Commons Attribution 4.0 International (CC BY 4.0) License by the author." >Some rights reserved.</span></p><p>Powered by <a href="https://jekyllrb.com" target="_blank" rel="noopener">Jekyll</a> with <a data-bs-toggle="tooltip" data-bs-placement="top" title="v7.5.0" href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank" rel="noopener" >Chirpy</a> theme.</p></footer></div></div><div id="search-result-wrapper" class="d-flex justify-content-center d-none"><div class="col-11 content"><div id="search-hints"><section><h2 class="panel-heading">Trending Tags</h2><div class="d-flex flex-wrap mt-3 mb-1 me-3"> <a class="post-tag btn btn-outline-primary" href="/tags/net6/">.NET6</a> <a class="post-tag btn btn-outline-primary" href="/tags/c-10/">C#10</a> <a class="post-tag btn btn-outline-primary" href="/tags/domain-driven-design/">Domain-driven Design</a> <a class="post-tag btn btn-outline-primary" href="/tags/eventsourcing/">EventSourcing</a> <a class="post-tag btn btn-outline-primary" href="/tags/microservices/">Microservices</a> <a class="post-tag btn btn-outline-primary" href="/tags/cqrs/">CQRS</a> <a class="post-tag btn btn-outline-primary" href="/tags/ienumerable/">IEnumerable</a> <a class="post-tag btn btn-outline-primary" href="/tags/linq/">Linq</a> <a class="post-tag btn btn-outline-primary" href="/tags/net7/">.NET7</a> <a class="post-tag btn btn-outline-primary" href="/tags/asp-net-core/">ASP.NET Core</a></div></section></div><div id="search-results" class="d-flex flex-wrap justify-content-center text-muted mt-3"></div></div></div></div><aside aria-label="Scroll to Top"> <button id="back-to-top" type="button" class="btn btn-lg btn-box-shadow"> <i class="fas fa-angle-up"></i> </button></aside></div><div id="mask" class="d-none position-fixed w-100 h-100 z-1"></div><aside id="notification" class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-bs-animation="true" data-bs-autohide="false" ><div class="toast-header"> <button type="button" class="btn-close ms-auto" data-bs-dismiss="toast" aria-label="Close" ></button></div><div class="toast-body text-center pt-0"><p class="px-2 mb-3">A new version of content is available.</p><button type="button" class="btn btn-primary" aria-label="Update"> Update </button></div></aside>
5<script> document.addEventListener('DOMContentLoaded', () => { SimpleJekyllSearch({ searchInput: document.getElementById('search-input'), resultsContainer: document.getElementById('search-results'), json: '/assets/js/data/search.json', searchResultTemplate: '<article class="px-1 px-sm-2 px-lg-4 px-xl-0"><header><h2><a href="{url}">{title}</a></h2><div class="post-meta d-flex flex-column flex-sm-row text-muted mt-1 mb-1"> {categories} {tags}</div></header><p>{content}</p></article>', noResultsText: '<p class="mt-5">Oops! No result founds.</p>', templateMiddleware: function(prop, value, template) { if (prop === 'categories') { if (value === '') { return `${value}`; } else { return `<div class="me-sm-4"><i class="far fa-folder fa-fw"></i>${value}</div>`; } } if (prop === 'tags') { if (value === '') { return `${value}`; } else { return `<div><i class="fa fa-tag fa-fw"></i>${value}</div>`; } } } }); }); </script>
vendor: 1 bytes, line 5
5

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.