JwtDecoder.Core
1.0.1
See the version list below for details.
dotnet add package JwtDecoder.Core --version 1.0.1
NuGet\Install-Package JwtDecoder.Core -Version 1.0.1
<PackageReference Include="JwtDecoder.Core" Version="1.0.1" />
<PackageVersion Include="JwtDecoder.Core" Version="1.0.1" />
<PackageReference Include="JwtDecoder.Core" />
paket add JwtDecoder.Core --version 1.0.1
#r "nuget: JwtDecoder.Core, 1.0.1"
#:package JwtDecoder.Core@1.0.1
#addin nuget:?package=JwtDecoder.Core&version=1.0.1
#tool nuget:?package=JwtDecoder.Core&version=1.0.1
JwtDecoder.Core
Offline, hardened JSON Web Token decoding and signature verification for .NET 8+.
This is the shared core library that powers:
jwtdecode— single-file Native AOT CLI for Windows, Linux, and macOS.JwtDecoder— PowerShell 7.4+ binary module.
Why another JWT library?
Most JWT libraries try to cover the whole identity workflow — issuance, refresh, JWKS discovery, OIDC flows, key rotation. That's exactly the kind of code that grows attack surface faster than tests can cover it. JwtDecoder.Core does one thing only: it takes a compact JWS token and (optionally) a verification key, and tells you whether the signature checks out.
Hardening properties
- Offline by design — never opens a socket. Filesystem reads are the only side-channel.
- AOT-safe — no reflection-based serialization, no dynamic code, zero NuGet dependencies. Works in
PublishAotapps. - Algorithm-confusion guard — refuses to verify an
HS*token with a PEM-looking key file. - Private-key refusal — PEM blocks labelled
PRIVATE KEYare rejected; verification only needs the public key. - JOSE curve binding —
ES256↔P-256,ES384↔P-384,ES512↔P-521. Mismatched curves are refused. - Constant-time HMAC comparison via
CryptographicOperations.FixedTimeEquals. - DoS-bounded I/O — token ≤ 1 MiB, key file ≤ 64 KiB, decoded segment ≤ 256 KiB, JSON
MaxDepth = 64. - Memory hygiene — secret bytes, decoded buffers, signing input, intermediate base64 / char arrays are all zeroed in
Dispose/finally. - Strict parsing — duplicate header/payload property names are rejected (parser-differential defense);
alg: nonealways returnsVerified=false.
Install
dotnet add package JwtDecoder.Core
Usage
The JwtTools static class is the easiest entry point:
using JwtDecoder.Core;
// Decode only (no signature check)
using var jwt = JwtTools.Decode(token);
Console.WriteLine(jwt.Algorithm); // e.g. "HS256"
Console.WriteLine(jwt.Payload.RootElement.GetProperty("sub").GetString());
// One-shot HMAC verification
var outcome = JwtTools.VerifyHmac(token, "your-256-bit-secret");
Console.WriteLine(outcome.Verified ? "OK" : $"Failed: {outcome.Error}");
// Decode + verify HMAC in one call (avoids double-parsing the token)
var (decoded, hmacResult) = JwtTools.DecodeAndVerifyHmac(token, secretBytes);
using (decoded)
{
if (hmacResult.Verified)
{
var role = decoded.Payload.RootElement.GetProperty("role").GetString();
// ...
}
}
// RSA / RSA-PSS (RS256/384/512, PS256/384/512)
using var rsa = RSA.Create();
rsa.ImportFromPem(pemString);
var rsaResult = JwtTools.VerifyRsa(token, rsa);
// ECDsa (ES256/384/512)
using var ec = ECDsa.Create();
ec.ImportFromPem(pemString);
var ecResult = JwtTools.VerifyEcdsa(token, ec);
// File-based — same rules as the CLI (alg inferred + cross-checked against file)
var fileResult = JwtTools.VerifyWithKeyFile(token, "./hs256-secret.txt");
If you need more control (e.g. reusing an RSA across many verifications, owning the KeyMaterial lifetime, or accessing the raw signing input), drop down to the underlying Jwt, JwtVerifier, KeyMaterial, and KeyLoader types directly — JwtTools is just a thin convenience layer over them.
Supported algorithms
| Family | Algorithms | Key type accepted |
|---|---|---|
| HMAC | HS256, HS384, HS512 | Raw secret bytes |
| RSA-PKCS#1 | RS256, RS384, RS512 | RSA public key |
| RSA-PSS | PS256, PS384, PS512 | RSA public key |
| ECDSA | ES256, ES384, ES512 | EC public key (curve-bound) |
alg: none is parseable for inspection but always returns Verified=false with a clearly worded security warning in VerifyOutcome.Error.
License
MIT — see LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on JwtDecoder.Core:
| Package | Downloads |
|---|---|
|
JwtDecoder.JwksFetcher
JWKS acquisition and OIDC discovery companion library for JwtDecoder.Core. Network-capable: fetches a JWKS (or discovers one via OIDC), validates it, selects the JWK matching a JWT's kid/alg/crv, and emits the public key as PEM. Defense in depth: HTTPS only, SSRF guards (including DNS rebinding via ConnectCallback and IPv4-mapped IPv6 unmapping), TLS 1.2/1.3 pinned, bounded sizes/timeouts/redirects, no on-disk cache, bearer stripped on every redirect. |
GitHub repositories
This package is not used by any popular GitHub repositories.