Changes ======= v1.2.6 24 Aug 2021 [New features] * Support `crypto.Signer` keys for RSA, ECDSA, and EdDSA family of signatures in `jws.Sign` [Miscellaneous] * `jwx.GuessFormat()` now requires the presense of both `payload` and `signatures` keys for it to guess that a JSON object is a JWS message. * Slightly enhance `jwt.Parse()` performance. v1.2.5 04 Aug 2021 [New features] * Implement RFC7797. The value of the header field `b64` changes how the payload is treated in JWS * Implement detached payloads for JWS * Implement (jwk.AutoRefresh).ErrorSink() to register a channel where you can receive errors from fetches and parses that occur during JWK(s) retrieval. v1.2.4 15 Jul 2021 [Bug fixes] * We had the same off-by-one in another place and jumped the gun on releasing a new version. At least we were making mistakes uniformally :/ `(jwk.Set).Remove` should finally be fixed. [New features] * `(jwk.Set).Clone()` has been added. v1.2.3 15 Jul 2021 [Bug fixes] * jwk.Set incorrectly removed 2 elements instead of one. [Miscellaneous] * github.com/goccy/go-json has been upgraded to v0.7.4 v1.2.2 13 Jul 2021 [Deprecation notice] * `(jwe.Message).Decrypt()` will be removed from the API upon the next major release. [Bug Fixes] * `jwe.Decrypt` and `(jwe.Message).Decrypt()` failed to decrypt even with the correct message contents when used along with `jwe.RegisterCustomField` [New features] JWX * Add GuessFormat() function to guess what the payload is. JWT * Options `jwt.WithMinDelta()`, `jwt.WithMaxDelta()` have been added. These can be used to compare time-based fields in the JWT object. * Option `jwt.WithRequiredClaim()` has been added. This can be used to check that JWT contains the given claim. * `jwt.Parse` now understands payloads that have been encrypted _and_ signed. This is more in line with the RFC than the previous implementation, but due to the fact that it requires a couple of extra unmarshaling, it may add some amount of overhead. * `jwt.Serializer` has been added as an easy wrapper to perform multiple levels of serializations (e.g. apply JWS, then JWE) JWE * Option `jwe.WithMessage()` has been added. This allows the user to obtain both the decrypted payload _and_ the raw `*jwe.Message` in one go when `jwe.Decrypt()` is called * Option `jwe.WithPostParser()`, along with `jwe.PostParser` and `jwe.PostParseFunc` has been added. This allows advanced users to hook into the `jwe.Decrypt()` process. The hook is called right after the JWE message has been parsed, but before the actual decryption has taken place. * `(jwe.Message).Decrypt()` has been marked for deprecation in a next major release. JWS * Option `jwe.WithMessage()` has been added. This allows the user to obtain both the verified payload _and_ the raw `*jws.Message` in one go when `jws.Verify()` is called * Options to `jws.Sign()` are not of type `jws.SignOption`. There should be no user-visible effects unless you were storing these somewhere. v1.2.1 02 Jun 2021 [New features] * Option `jwt.WithTypedClaim()` and `jwk.WithTypedField()` have been added. They allow a per-object custom conversion from their JSON representation to a Go object, much like `RegisterCustomField`. The difference is that whereas `RegisterCustomField` has global effect, these typed fields only take effect in the call where the option was explicitly passed. `jws` and `jwe` does not have these options because (1) JWS and JWE messages don't generally carry much in terms of custom data (2) This requires changes in function signatures. Only use these options when you absolutely need to. While it is a powerful tool, they do have many caveats, and abusing these features will have negative effects. See the documentation for details v1.2.0 30 Apr 2021 This is a security fix release with minor incompatibilities from earlier version with regards to the behavior of `jwt.Verify()` function [Security Fix] * `jwt.Verify()` had improperly used the `"alg"` header from the JWS message when `jwt.WithKeySet()` option was used (potentially allowing exploits described in https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/. This has been fixed by ONLY trusting the keys that you provide and using the `"alg"` header from the keys themselves. (#375, #381) As a side effect, `jwt.WithKeySet()` requires that all applicable keys to contain a valid `"alg"` header. Without this we cannot safely choose a key to use, and hence verification will fail. The requirement for the `"alg"` header on keys is an INCOMPATIBLE behavior. This may break existing code, if the key does not already have an `"alg"` header. [New features] * `jwt.Settings()` and `jwt.WithFlattenAudience(bool)` has been added to control how the "aud" claim is serialized into JSON. When this is enabled, all JWTs with a single "aud" claim will serialize the field as a single string, instead of an array of strings with a single element, i.e.: // jwt.WithFlattenAudience(true) {"aud": "foo"} // jwt.WithFlattenAudience(false) {"aud": ["foo"]} This setting has a global effect. [Buf fixes] * jwt.Validate now returns true if the value in `nbf` field is exactly the same as what the clock returns (e.g. token.nbf == time.Now()) v1.1.7 02 Apr 2021 [New features] * `jwk.New` `jwk.Parse`, `jwk.ParseKey` can now take a Certificate in ASN.1 DER format in PEM encoding to create a JWK. [Bug fixes] * Protect `jwk.New()` from invalid RSA/ECDSA keys (#360, #361) [Miscellaneous] * Removed "internal/blackmagic" and separated it to its own repository. * Removed unused "marshal proxy" objects in jwt * Added FAQ in `jwt` package v1.1.6 28 Mar 2021 [Bug fixes] * When an object (e.g. JWT) has a null value and `AsMap()` is called, `github.com/lestrrat-go/iter` would panic. This should be fixed in `github.com/lestrrat-go/iter@v1.0.1` and the dependency has been updated accordingly [Miscellaneous] * Added How-to style docs under `docs/` * github.com/goccy/go-json dependency has been updated to v0.4.8 v1.1.5 12 Mar 2021 This is a security fix release. The JWT validation could be skipped for empty values. Upgrade recommended [Security Fix] * JWT validation could be skipped for empty fields (#352). [Bug fixes] * Allow setting JWT "typ" fields to any value (#351). * Remove stray replace directive in cmd/jwx/go.mod (#349) v1.1.4 02 Mar 2021 [New features] * jwt.ParseRequest, jwt.ParseHeader, jwt.ParseForm have been added. They are convenience functions to parse JWTs out of a HTTP request. [Miscellaneous] * Fix jwt.Equals() so that comparison between values containing time.Time actually work * ES256K has been made non-default. You must enable it using a build tag go build -tags jwx_es256k ... Your program will still compile without this tag, but it will return an error during runtime, when ES256K is encountered. This feature is still experimental. v1.1.3 22 Feb 2021 [New features] * Implemented ES256K signing (#337) This feature should be considered experimental [Miscellaneous] * Bump minimum required version to go1.15 * Fix examples, bench, and cmd/jwx accidentally requiring go1.16 * Dependencies for "github.com/goccy/go-json" has been upgraded to v0.4.7 v1.1.2 16 Feb 2021 [New features] * `RegisterCustomField()` has been added, which allows users to specify a private claim/field/header to decode into a particular object of choice, instead of map[string]interface{} or []interface{} (#332, #333) [Bug fixes] * Failures for `jwk.Key.MarshalJSON()` were not properly reported (#330, #331) [Miscellaneous] * `jwe.Encrypt()` now takes options. This should not matter unless you were somehow depending on its method signature. * Dependencies for "github.com/goccy/go-json" has been upgraded to v0.4.2 v1.1.1 05 Feb 2021 [New features] * Command line tool `jwx` has ben completely reworked, and it is now actually useful. * JWKs can now be serialized into PEM files with ASN.1 DER format data, which is useful when you need to work between JSON and PEM data formats. * Constants in jwa package now have can be listed via functions in each category. * jwe.Encrypt and jwe.Decrypt can now handle jwk.Key objects v1.1.0 31 Jan 2021 v1.1.0 is a release that attempts to fix as many of the quirky APIs that survived the API breaking change of v0.9.x -> v1.0.0. This is hopefully the last releases that change backwards compatibility in a major way, at least for some time to come. It is unfortunate that we need to introduce API changes, but we keep learning how the library is being used and the pain points of using this library. Most of the times these pain points are things that we initially did not think about, which in turn requires us to rethink of the API. If you do not wish to spend the time fixing your usage, make sure you have your go.mod set up to not automatically track the latest changes. However, if you do decide to use the latest version, we believe the API is more uniform across packages, and generally is easier to understand. We hope this library helps some of you out there. [BREAKING CHANGES] * `jwk.Parse(io.Reader)`, `jws.Parse(io.Reader)`, `jwt.Parse(io.Reader)`, have all been changed to `Parse([]byte)`. To use an `io.Reader`, use `ParseReader(io.Reader)`. `jwe.Parse` already took `[]byte`, so has not been changed. With this change, all four package `jwe`, `jwk`, `jws`, and `jwt` follow the same API design, which should make things easier to navigate: Parse([]byte) ParseString(string) ParseReader(io.Reader) * `jwk.Set` is now an interface, not a struct. `jwk.Set` now has a well-defined API to access and modify the `jwk.Key` objects that it holds. Add(jwk.Key) bool Clear() Get(int) (jwk.Key, bool) Index(jwk.Key) int Len() int LookupKeyID() (jwk.Key, bool) // Read the section about it below Remove(jwk.Key) bool Iterate(context.Context) KeyIterator * `(jwk.Set).LookupKeyID()` no longer returns an array of `jwk.Key`. Instead, only the first key matching the given key ID will be returned. If you need to work with multiple keys, use `(jwk.Set).Iterate()` or `(jwk.Set).Get()` to look for matching keys. * `jwk.PublicKeyOf()` has been renamed to `jwk.PublicRawKeyOf()`, which converts raw keys (e.g. `rsa.PrivateKey`) to their public counter part (e.g. `rsa.PublicKey`) `jwk.PublicKeyOf()` is now used to get the public counter part of `jwk.Key` objects (e.g. `jwk.RSAPrivateKey` to `jwk.RSAPublicKey`) `jwk.PublicSetOf()` has been added to get a new `jwk.Set` but with all keys transformed to public keys via `jwk.PublicKeyOf()` * `jwk.FetchXXXX` functions have been removed. `jwk.Fetch()` remains, but it now takes `context.Context`, and doesn't support retrieving files from the local file system. See `ReadFile()` for that. * `jws.VerifyWithJKU()`, `jws.VerifyWithJWK()`, `jwk.VerifyWithJWKSet()` have all been removed, but `jwk.VerifySet(jwk.Set)` has been added. * `jws.SplitCompact(io.Reader)` has been changd to `jws.SplitCompact([]byte)` Similar to `Parse()`, `SplitCompactReader(io.Reader)` and `SplitCompactString(string)` have been added * `jws.SignLiteral` has been removed. * `jws.PayloadSigner` has been removed (but should not matter, because this as internal-use only anyways) * `jwe.WithPrettyJSONFormat` has been renamed to `jwe.WithPrettyFormat` * `jwt.Verify` has been removed. Use `jwt.Parse()` aloing with the `jwt.WithVerify()` option to perform signature verification. Validation of verified data can be performed via `(jwt.Token).Validate()` method, which has been available since v1.0.6 * Package `buffer` has been removed. This package should have been an internal package to start with, but it was left because it had been incorporated in the public API in our initial versions. * `(jwk.Key).Get(jwk.X509CertChainKey)` no longer returns a `jwk.CertificateChain`. Instead it returns a raw []*x509.Certificate. * `(jwt.Token).Size() has been removed. * `jwt.WithOpenIDClaims()` has been removed. Use `jwt.WithToken(openid.New())` instead. [New Features] * `jwe.ReadFile(string)`, `jwk.ReadFile(string)`, `jws.ReadFile(string)`, and `jwt.ReadFile(string)` have been added. In the future, we plan to introduce a `WithFS` option so you can read from an arbitrary file system, but this cannot be added while we keep go < 1.16 compatibility. If you want something like that, you will need to put an adapter over the jwx for the time being. * `(jwk.Key).PublicKey()` has been added. This method creates a corresponding public key, with all fields (except those that shouldn't be) copied over. This allows you to easily create a public key of a private key with the same "kid" attribute. * Both `jws.Verify` and `jws.Sign` methods can now handle `jwk.Key` objects, on top of raw keys (e.g. rsa.PrivateKey). You no longer need to conver the `jwk.Key` objects that you have in to raw keys before using these functions. * `(jws.Header).Remove(string)`, `(jwk.Key).Remove(string)`, and `(jwt.Token).Remove(string)` have been added. `jwe.Header` already had a `Remove()` method, so it has not been changed. * `(jwk.Key).Clone() has been added. [Miscellaneous] * Default branch for the repository is now `main`. * Options have been reworked. In most instances, option types should now reflect better the contexts in which they can be used. For example, `jwk` now has `AutoRefreshOption` and `FetchOption` instead of a single `Option`. * JSON marshaling should be 10~30% faster by default (though they may take more allocations to achieve this). However, if performance is really bogging you down, you can try to enable the optional module github.com/goccy/go-json by enabling the "jwx_goccy" tag go build -tags jwx_goccy ... In some cases you get an extra 40~50% performance improvement in serailization https://github.com/lestrrat-go/jwx/pull/314#issue-560594020 https://github.com/lestrrat-go/jwx/pull/314#issuecomment-766343888 * Location for examples and benchmarks have changed: Now examples/ and bench/ are their respective locations, and they are each a standalone module, so that in case we need extra imports (such as the case in examples) they do not interfere with users who just want to include jwx in their projects. v1.0.8 15 Jan 2021 [New features] * Fixed `jws.Message` and `jws.Signature` to be properly formatted when marshaled into JSON. In the same manner, `json.Unmarshal` should also work as expected. * Added API to programatically manipulate `jws.Message` and `jws.Signature` [Miscellaneous] * The order of keys are now consistent as when used with `json.Marshal`. Previously some objects used their own ordering, but now the code goes through one extra roundtrip of `json.Unmarshal`/`json.Marshal` to preserve compatible behavior. This *may* lead to slightly slower performance if you are performing `json.Marshal` over and over in very quick succession. Please file an issue if you have real world cases where the change causes problems for you. * Added more examples in various places. * Tests runs have been sped up for the most oft used cases v1.0.7 11 Jan 2021 [New features] * Added jwk.AutoRefresh, which is a tool to periodically refresh JWKS. (#265) * Added experimental ed25519 support (#252) [Bug fixes] * Fix `Set()` method for jwk Keys to properly accept either `jwk.KeyUsageType` or a simple string. [Miscellaneous] * Updated dependencies * Changed options to use github.com/lestrrat-go/option * Various typos, unused annotations, etc, have been fixed by contributors * Nobody except for the author really should care, but the underlying `pdebug` utility, which is used for print debugging, has been upgraded to v3, which should stop parallel test execution from throwing an error when run with -race v1.0.6 17 Dec 2020 * Fix ECDHES ciphers where padding in AAD et al was creating incomptabile values with jose tool * Also fix ECDH-ES cek handling (#248) * Implement direct key encoding (#213, #249) * Allow JWT tokens to use default JWK if only one key is given and the JWT does not necessarily specifies a key (#214) * Deprecate jwt.Verify and introduce jwt.Validate. JWS verification used the term Verify, which was confusing when users wanted to validate the JWT token itself. (#220) * JWT library optins have been explicitly typed as ValidationOption and ParseOption (#220, #223) * Add jwx.DecoderSettings and jwx.WithUseNumber option to globally change how jwx parses JSON objects (#222) * Encode x5c field as base64 with padding (#244) * Add more interoperability tests against jose tool. * Special thanks to anatol and imirkin! v1.0.5 - 28 Sep 2020 * Reinstate PrivateParams() method in jws and jwe packages. These used to be available until v1.0.0, but somehow got lost during the big change. As a workaround for users of versions 1.0.0 to 1.0.4, you could have achieved the same thing using AsMap() methods, albeit with a slight performance penality (#205, #206) v1.0.4 - 15 Aug 2020 * Fix jwt.WithOpenIDClaims(). Looks like something got lost along the way, and it never really worked. (#201 #202) v1.0.3 - 08 Jul 2020 * `jws.Sign`, and therefore `jwt.Sign` now accept `jwk.Key` as the key to use for signature. (#199) * `jwt.Sign` could sometimes return a nil error when setting bad values to the protected header failed (#195) * More golangci-lint cleanup (#193) v1.0.2 - 07 May 2020 * Since 1.0.0, we took some time to play the test coverage game. The coverage is around 30% better, and we _did_ uncover some inconsistencies in the API, which got promptly fixed. But I'm tired of the coverage game for the time being. PR's welcome! * Add jwk.AssignKeyID to automatically assign a `kid` field to a JWK * Fix jwe.Encrypt / jwe.Decrypt to properly look at the `zip` field * Change jwe.Message accessors to return []byte, not buffer.Buffer v1.0.1 - 04 May 2020 * Normalize all JWK serialization to use padding-less base64 encoding (#185) * Fix edge case unmarshaling openid.AddressClaim within a openid.Token * Fix edge case unmarshaling jwe.Message * Export JWK key-specific constants, such as jwk.RSANKey, jwk.SymmetricOctetsKey, etc * Remove some unused code v1.0.0 - 03 May 2020 * All packages (`jws`, `jwe`, `jwk`, `jwt`) have all been reworked from the ground-up. * These packages now hide the actual implementation of the main structs behind an interface. * Header/Token structs must now be instantiated using proper constructors (most notably, json.Unmarshal will miserably fail if you just pass and empty interface via `xxx.Token` or similar) * Token/Header interfaces are now more or less standardized. The following API should be consistent between all relevant packages: * New() * Get() * Set() * Remove() * Iterate() * Walk() * AsMap() * Oft-used fields are no longer directly accessible: e.g. `token.KeyID = v` is no longer valid. You must set using `Set` (and `Remove`, if you are removing it), and use either `Get` or one of the utility methods such as `token.KeyID()` * Many helper functions and structs have been unexported. They were never meant to be anything useful for end-users, and hopefully it does not cause any problems. * Most errors type/instances have been removed from the public API * `jwt` package can now work with different token types, such as OpenID tokens. * `token.Sign` and `token.Verify` have been changed from methods to package functions `jwt.Sign` and `jwt.Verify`, to allow different types of tokens to be passed to the same logic. * Added a custom token type in `openid` sub-package to make it easier to work with OpenID claims * `jwt.Parse` (and its siblings) now accept `jwt.WithOpenIDClaims()` * `jwe` API has been reworked: * `MultiEncrypt` has been removed. * Serializer structs have been removed. Now you just need to call `jwe.Compact` or `jwe.JSON` * `jwk` API has been reworked: * `jwk.ParseKey` has been added * `jwk.Materialize` has been renamed to `Raw()`. A new corresponding method to initialize the key from a raw key (RSA/ECDSA/byte keys) called `FromRaw()` has also been added, which makes a nice pair. * `jws` API has been reworked * CI has been changed from Travis CI to Github Actions, and tests now include linting via `golangci-lint` v0.9.2 - 15 Apr 2020 * Maintenance release to protect users from upcoming breaking changes v0.9.1 - 27 Feb 2020 * Fix error wrapping in certain cases * Add Claims(), Walk(), and AsMap() to iterate claims, as well as getting the entire data out as a single map * Work with alternate base64 encodings when decoding v0.9.0 - 22 May 2019 * Start tagging versions for good measure.