Changelog
Notable changes in each release.
All notable changes to ArturRios.Jwt are recorded in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
1.4.0 - 2026-10-16
Added
- ES256 (ECDSA P-256 with SHA-256) beside HS256.
JwtKey.FromEcPrivateKeyPemreads a P-256 private key from a PEM,JwtKey.FromEcPublicJwkbuilds a verification key from a JWK’sxandy, andToPublicKeydrops the private half. An EC key’sIdis its RFC 7638 thumbprint (Thumbprint), derived and never configured. JwtConfiguration.Algorithm:JwtAlgorithms.HS256, the default, orJwtAlgorithms.ES256. An ES256 configuration signs with the private keySigningKeyIdnames inKeys, and its tokens carry that key’s thumbprint askid.JwksDocument.From(keys)writes a JSON Web Key Set holding only public halves, refusing a key whose id is not its thumbprint, andJwksDocument.Parse(json)reads one into verification keys.Parseskips entries that are not EC P-256 signing keys, whosekidis not their thumbprint, or that carry a private part (d), since a published private part means the key is compromised. It returns each key once, skipping an entry whose id repeats an earlier one, and skips an entry it cannot decode, such as one holding a lone surrogate escape (\uD800). A document that is not a key set throwsFormatException, and so does the same undecodable text in the key set’s own member names.JwtKey.Algorithm,IsAsymmetric,CanSignandToSecurityKey().
Changed
JwtConfigurationValidatorholds a configuration to itsAlgorithm: an HS256 one may not hold an EC key, and an ES256 one must hold EC keys only, each named by its thumbprint, sign with one that has its private half, and leaveSecretempty. HS256 configurations validate exactly as before.
Security
- Each key validates its own algorithm only — an EC key ES256, a secret HS256 — whatever the token’s
algheader says, so an HS256 token keyed with a published public key, or an unsigned one, is refused.IsTokenValidAsync(token, keys)throwsArgumentExceptionfor a key set that mixes the two kinds.
1.3.0 - 2026-10-15
Changed
JwtConfigurationValidatorrejects every configurationCreateTokencannot sign with, or whose tokens the configured keys would not accept: a signingSecret(one used because noSigningKeyIdis set) is required even whenKeysis set, must be at least 32 bytes, and must be the secret of one of theKeyswhen there are any; and every key inKeysmust have a secret of at least 32 bytes. Each of these configurations used to pass validation and then throw inCreateToken, or issue tokens that failed validation againstKeys.
Fixed
IsTokenValidAsyncreturnsfalsefor a blank secret, and the key-set overload treats a key with a blank secret as accepting nothing, instead of both throwingArgumentExceptionfromSymmetricSecurityKey.
Security
IsTokenValidAsyncaccepts onlyHS256signatures, the one algorithmCreateTokenuses, instead of any HMAC algorithm the token’salgheader names.
1.2.0 - 2026-08-24
Changed
GetUserIdFromTokenandGetKeyIdFromTokenreturnnullfor input they cannot read — a token with noidclaim, a non-integerid, or a token whose segments are not valid base64url — instead of throwing, as they always documented.CreateTokenstampsnbfandexpfrom UTC rather than local time.System.IdentityModel.Tokens.Jwtupdated from 8.19.1 to 8.22.0.
Fixed
CreateTokenno longer builds a secondJwtSecurityTokenHandleron every call.
1.1.0 - 2026-08-17
Added
- Signing key rotation:
JwtConfiguration.KeysandSigningKeyIdlet one key sign while several are accepted. Tokens carry the signing key’s id in theirkidheader. JwtHandler.IsTokenValidAsync(token, keys)validates a token against a set of keys.JwtHandler.GetKeyIdFromTokenreads thekidthat names a token’s signing key.
Changed
JwtConfiguration.Secretis required only when noKeysare configured.
1.0.0 - 2026-07-02
Added
JwtConfiguration, andJwtConfigurationValidatorto check it with FluentValidation.JwtHandlerto create HMAC-SHA256 signed tokens, validate them against a secret, and read the user id from a token’sidclaim.