Changes
=======

v3 has many incompatibilities with v2. To see the full list of differences between
v2 and v3, please read the Changes-v3.md file (https://github.com/lestrrat-go/jwx/blob/develop/v3/Changes-v3.md)

v3.0.13 12 Jan 2026
  * [jwt] The `jwt.WithContext()` option is now properly being passed to `jws.Verify()` from
    `jwt.Parse()`.
  * [jwx] github.com/lestrrat-go/httprc/v3 has been upgraded to remove dependency on 
    github.com/lestrrat-go/option (v1)
  * [jwk] `jwk.Clone()` has been fixed to properly work with private fields.

v3.0.12 20 Oct 2025
  * [jwe] As part of the next change, now per-recipient headers that are empty
    are no longer serialized in flattened JSON serialization.

  * [jwe] Introduce `jwe.WithLegacyHeaderMerging(bool)` option to control header
    merging behavior in during JWE encryption. This only applies to flattened
    JSON serialization.

    Previously, when using flattened JSON serialization (i.e. you specified
    JSON serialization via `jwe.WithJSON()` and only supplied one key), per-recipient
    headers were merged into the protected headers during encryption, and then
    were left to be included in the final serialization as-is. This caused duplicate
    headers to be present in both the protected headers and the per-recipient headers.

    Since there may be users who rely on this behavior already, instead of changing the
    default behavior to fix this duplication, a new option to `jwe.Encrypt()` was added
    to allow clearing the per-recipient headers after merging to leave the `"headers"`
    field empty. This in effect makes the flattened JSON serialization more similar to
    the compact serialization, where there are no per-recipient headers present, and
    leaves the headers disjoint.
    
    Note that in compact mode, there are no per-recipient headers and thus the
    headers need to be merged regardless. In full JSON serialization, we never
    merge the headers, so it is left up to the user to keep the headers disjoint.

  * [jws] Calling the deprecated `jws.NewSigner()` function for the first time will cause
    legacy signers to be loaded automatically. Previously, you had to explicitly
    call `jws.Settings(jws.WithLegacySigners(true))` to enable legacy signers.

    We incorrectly assumed that users would not be using `jws.NewSigner()`, and thus
    disabled legacy signers by default. However, it turned out that some users
    were using `jws.NewSigner()` in their code, which lead to breakages in 
    existing code. In hindsight we should have known that any API made public before will
    be used by _somebody_.

    As a side effect, jws.Settings(jws.WithLegacySigners(...)) is now a no-op.

    However, please do note that jws.Signer (and similar) objects were always intended to be
    used for _registering_ new signing/verifying algorithms, and not for end users to actually
    use them directly. If you are using them for other purposes, please consider changing
    your code, as it is more than likely that we will somehow deprecate/remove/discouraged
    their use in the future.

v3.0.11 14 Sep 2025
  * [jwk] Add `(jwk.Cache).Shutdown()` method that delegates to the httprc controller
    object, to shutdown the cache.
  * [jwk] Change timing of `res.Body.Close()` call
  * [jwe] Previously, ecdh.PrivateKey/ecdh.PublicKey were not properly handled
    when used for encryption, which has been fixed.
  * [jws/jwsbb] (EXPERIMENTAL/BREAKS COMPATIBILITY) Convert most functions into
    thin wrappers around functions from github.com/lestrrat-go/dsig package.
    As a related change, HAMCHashFuncFor/RSAHashFuncFor/ECDSAHashFuncFor/RSAPSSOptions
    have been removed or unexported.
    Users of this module should be using jwsbb.Sign() and jwsbb.Verify() instead of
    algorithm specific jwsbb.SignRSA()/jwsbb.VerifyRSA() and such. If you feel the
    need to use these functions, you should use github.com/lestrrat-go/dsig directly.

v3.0.10 04 Aug 2025
  * [jws/jwsbb] Add `jwsbb.ErrHeaderNotFound()` to return the same error type as when
    a non-existent header is requested. via `HeaderGetXXX()` functions. Previously, this
    function was called `jwsbb.ErrFieldNotFound()`, but it was a misnomer.
  * [jws/jwsbb] Fix a bug where error return values from `HeaderGetXXX()` functions
    could not be matched against `jwsbb.ErrHeaderNotFound()` using `errors.Is()`.

v3.0.9 31 Jul 2025
  * [jws/jwsbb] `HeaderGetXXX()` functions now return errors when
    the requested header is not found, or if the value cannot be
    converted to the requested type.

  * [jwt] `(jwt.Token).Get` methods now return specific types of errors depending
    on if a) the specified claim was not present, or b) the specified claim could
    not be assigned to the destination variable.

    You can distinguish these by using `errors.Is` against `jwt.ClaimNotFoundError()`
    or `jwt.ClaimAssignmentFailedError()`

v3.0.8 27 Jun 2025
  * [jwe/jwebb] (EXPERIMENTAL) Add low-level functions for JWE operations.
  * [jws/jwsbb] (EXPERIMENTAL/BREAKS COMPATIBILITY) Add io.Reader parameter
    so your choice of source of randomness can be passed. Defaults to crypto/rand.Reader.
    Function signatures around jwsbb.Sign() now accept an addition `rr io.Reader`,
    which can be nil for 99% of use cases.
  * [jws/jwsbb] Add HeaderParse([]byte), where it is expected that the header
    is already in its base64 decoded format.
  * misc: replace `interface{}` with `any`

v3.0.7 16 Jun 2025
  * [jws/jwsbb] (EXPERIMENTAL) Add low-level fast access to JWS headers in compact
    serialization form.
  * [jws] Fix error reporting when no key matched for a signature.
  * [jws] Refactor jws signer setup.
    * Known algorithms are now implemented completely in the jws/jwsbb package.
    * VerifierFor and SignerFor now always succeed, and will also return a Signer2
      or Verifier2 that wraps the legacy Signer or Verifier if one is registered.

v3.0.6 13 Jun 2025
  * This release contains various performance improvements all over the code.
    No, this time for real. In particular, the most common case for signing
    a JWT with a key is approx 70% more efficient based on the number of allocations.

    Please read the entry for the (retracted) v3.0.4 for what else I have to
    say about performance improvements

  * [jwt] Added fast-path for token signing and verification. The fast path
    is triggered if you only pass `jwt.Sign()` and `jwt.Parse()` one options each
    (`jwt.WithKey()`), with no suboptions.

  * [jws] Major refactoring around basic operations:

    * How to work with Signer/Verifier have completely changed. Please take
      a look at examples/jws_custom_signer_verifier_example_test.go for how
      to do it the new way. The old way still works, but it WILL be removed
      when v4 arrives.
    * Related to the above, old code has been moved to `jws/legacy`.

    * A new package `jws/jwsbb` has been added. `bb` stands for building blocks.
      This package separates out the low-level JWS operations into its own
      package. So if you are looking for just the signing of a payload with
      a key, this is it.

      `jws/jwsbb` is currently considered to be EXPERIMENTAL.

v3.0.5 11 Jun 2025
  * Retract v3.0.4
  * Code for v3.0.3 is the same as v3.0.3

v3.0.4 09 Jun 2025
  * This release contains various performance improvements all over the code.

    Because of the direction that this library is taking, we have always been
    more focused on correctness and usability/flexibility over performance.

    It just so happens that I had a moment of inspiration and decided to see
    just how good our AI-based coding agents are in this sort of analysis-heavy tasks.

    Long story short, the AI was fairly good at identifying suspicious code with
    an okay accuracy, but completely failed to make any meaningful changes to the
    code in a way that both did not break the code _and_ improved performance.
    I am sure that they will get better in the near future, but for now,
    I had to do the changes myself. I should clarify to their defence that
    the AI was very helpful in writing cumbersome benchmark code for me.

    The end result is that we have anywhere from 10 to 30% performance improvements
    in various parts of the code that we touched, based on number of allocations.
    We believe that this would be a significant improvement for many users.

    For further improvements, we can see that there would be a clear benefit to
    writing optimized code path that is designed to serve the most common cases.
    For example, for the case of signing JWTs with a single key, we could provide
    a path that skips a lot of extra processing (we kind of did that in this change,
    but we _could_ go ever harder in this direction). However, it is a trade-off between
    maintainability and performance, and as I am currently the sole maintainer of
    this library for the time being, I only plan to pursue such a route where it
    requires minimal effort on my part.

    If you are interested in helping out in this area, I hereby thank you in advance.
    However, please be perfectly clear that unlike other types of changes, for performance
    related changes, the balance between the performance gains and maintainability is
    top priority. If you have good ideas and code, they will always be welcome, but
    please be prepared to justify your changes.

    Finally, thank you for using this library!

v3.0.3 06 Jun 2025
  * Update some dependencies
  * [jwe] Change some error messages to contain more context information

v3.0.2 03 Jun 2025
  * [transform] (EXPERIMENTAL) Add utility function `transform.AsMap` to convert a
    Mappable object to a map[string]interface{}. This is useful for converting
    objects such as `jws.Header`, `jwk.Key`, `jwt.Token`, etc. to a map that can
    be used with other libraries that expect a map.
  * [jwt] (EXPERIMENTAL) Added token filtering functionality through the TokenFilter interface. 
  * [jwt/openid] (EXPERIMENTAL) Added StandardClaimsFilter() for filtering standard OpenID claims.
  * [jws] (EXPERIMENTAL) Added header filtering functionality through the HeaderFilter interface.
  * [jwe] (EXPERIMENTAL) Added header filtering functionality through the HeaderFilter interface.
  * [jwk] (EXPERIMENTAL) Added key filtering functionality through the KeyFilter interface.
  * [jwk] `jwk.Export` previously did not recognize third-party objects that implemented `jwk.Key`,
    as it was detecting what to do by checking if the object was one of our own unexported
    types. This caused some problems for consumers of this library that wanted to extend the
    features of the keys.

    Now `jwk.Export` checks types against interface types such as `jwk.RSAPrivateKey`, `jwk.ECDSAPrivateKey`, etc.
    It also uses some reflect blackmagic to detect if the given object implements the `jwk.Key` interface
    via embedding, so you should be able to embed a `jwk.Key` to another object to act as if it
    is a legitimate `jwk.Key`, as far as `jwk.Export` is concerned.

v3.0.1 29 Apr 2025
  * [jwe] Fixed a long standing bug that could lead to degraded encryption or failure to
    decrypt JWE messages when a very specific combination of inputs were used for
    JWE operations.

    This problem only manifested itself when the following conditions in content encryption or decryption
    were met:
      - Content encryption was specified to use DIRECT mode.
      - Contentn encryption algorithm is specified as A256CBC_HS512
      - The key was erronously constructed with a 32-byte content encryption key (CEK)

    In this case, the user would be passing a mis-constructed key of 32-bytes instead
    of the intended 64-bytes. In all other cases, this construction would cause
    an error because `crypto/aes.NewCipher` would return an error when a key with length
    not matching 16, 24, and 32 bytes is used. However, due to use using a the provided
    32-bytes as half CEK and half the hash, the `crypto/aes.NewCipher` was passed
    a 16-byte key, which is fine for AES-128. So internally `crypto/aes.NewCipher` would
    choose to use AES-128 instead of AES-256, and happily continue. Note that no other
    key lengths such as 48 and 128 would have worked. It had to be exactly 32.

    This does indeed result in a downgraded encryption, but we believe it is unlikely that this would cause a problem in the real world,
    as you would have to very specifically choose to use DIRECT mode, choose
    the specific content encryption algorithm, AND also use the wrong key size of
    exactly 32 bytes.

    However, in abandunce of caution, we recommend that you upgrade to v3.0.1 or later,
    or v2.1.6 or later if you are still on v2 series.

  * [jws] Improve performance of jws.SplitCompact and jws.SplitCompactString
  * [jwe] Improve performance of jwe.Parse

v3.0.0 1 Apr 2025
  * Release initial v3.0.0 series. Code is identical to v3.0.0-beta2, except
    for minor documentation changes.

    Please note that v1 will no longer be maintained.

    Going forward v2 will receive security updates but will no longer receive
    feature updates. Users are encouraged to migrate to v3. There is no hard-set
    guarantee as to how long v2 will be supported, but if/when v4 comes out,
    v2 support will be terminated then.

v3.0.0-beta2 30 Mar 2025
  * [jwk] Fix a bug where `jwk.Set`'s `Keys()` method did not return the proper
    non-standard fields. (#1322)
  * [jws][jwt] Implement `WithBase64Encoder()` options to pass base64 encoders
    to use during signing/verifying signatures. This useful when the token
    provider generates JWTs that don't follow the specification and uses base64
    encoding other than raw url encoding (no padding), such as, apparently,
    AWS ALB. (#1324, #1328)

v3.0.0-beta1 15 Mar 2025
  * [jwt] Token validation no longer truncates time based fields by default.
    To restore old behavior, you can either change the global settings by
    calling `jwt.Settings(jwt.WithTruncation(time.Second))`, or you can
    change it by each invocation by using `jwt.Validate(..., jwt.WithTruncation(time.Second))`

v3.0.0-alpha3 13 Mar 2025
  * [jwk] Importing/Exporting from jwk.Key with P256/P386/P521 curves to
    ecdh.PrivateKey/ecdh.PublicKey should now work. Previously these keys were not properly
    recognized by the exporter/importer. Note that keys that use X25519 and P256/P384/P521
    behave differently: X25519 keys can only be exported to/imported from OKP keys,
    while P256/P384/P521 can be exported to either ecdsa or ecdh keys.

v3.0.0-alpha2 25 Feb 2025
  * Update to work with go1.24
  * Update tests to work with latest latchset/jose
  * Fix build pipeline to work with latest golangci-lint
  * Require go1.23

v3.0.0-alpha1 01 Nov 2024
  * Initial release of v3 line.
