Repository: lestrrat-go/jwx
Pull request #600 (2022-03-04 05:09:39)

Generate jwk options

codecov-commenter: # [Codecov](https://codecov.io/gh/lestrrat-go/jwx/pull/600?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) Report
> Merging [#600](https://codecov.io/gh/lestrrat-go/jwx/pull/600?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) (b2bcd77) into [v2](https://codecov.io/gh/lestrrat-go/jwx/commit/bc5d2b97ef8e4d8cc1370043256dfb05b065c4ad?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) (bc5d2b9) will **decrease** coverage by `0.04%`.
> The diff coverage is `80.00%`.

[![Impacted file tree graph](https://codecov.io/gh/lestrrat-go/jwx/pull/600/graphs/tree.svg?width=650&height=150&src=pr&token=kU2RSDosPt&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go)](https://codecov.io/gh/lestrrat-go/jwx/pull/600?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go)

```diff
@@            Coverage Diff             @@
##               v2     #600      +/-   ##
==========================================
- Coverage   72.26%   72.21%   -0.05%     
==========================================
  Files          88       85       -3     
  Lines        9755     9749       -6     
==========================================
- Hits         7049     7040       -9     
- Misses       1901     1904       +3     
  Partials      805      805              
```


| [Impacted Files](https://codecov.io/gh/lestrrat-go/jwx/pull/600?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go) | Coverage Δ | |
|---|---|---|
| [jwk/jwk.go](https://codecov.io/gh/lestrrat-go/jwx/pull/600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andrL2p3ay5nbw==) | `60.96% <ø> (ø)` | |
| [jwk/options\_gen.go](https://codecov.io/gh/lestrrat-go/jwx/pull/600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andrL29wdGlvbnNfZ2VuLmdv) | `68.00% <76.19%> (ø)` | |
| [jwk/options.go](https://codecov.io/gh/lestrrat-go/jwx/pull/600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andrL29wdGlvbnMuZ28=) | `100.00% <100.00%> (ø)` | |
| [internal/ecutil/ecutil.go](https://codecov.io/gh/lestrrat-go/jwx/pull/600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-aW50ZXJuYWwvZWN1dGlsL2VjdXRpbC5nbw==) | `79.48% <0.00%> (-5.13%)` | :arrow_down: |
| [internal/json/goccy.go](https://codecov.io/gh/lestrrat-go/jwx/pull/600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-aW50ZXJuYWwvanNvbi9nb2NjeS5nbw==) | | |
| [jwa/secp2561k.go](https://codecov.io/gh/lestrrat-go/jwx/pull/600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andhL3NlY3AyNTYxay5nbw==) | | |
| [jwk/es256k.go](https://codecov.io/gh/lestrrat-go/jwx/pull/600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andrL2VzMjU2ay5nbw==) | | |
| [jws/es256k.go](https://codecov.io/gh/lestrrat-go/jwx/pull/600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go#diff-andzL2VzMjU2ay5nbw==) | | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/lestrrat-go/jwx/pull/600?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/lestrrat-go/jwx/pull/600?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go). Last update [bc5d2b9...b2bcd77](https://codecov.io/gh/lestrrat-go/jwx/pull/600?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lestrrat-go).


Patch:
diff --git a/internal/cmd/genoptions/gen.sh b/internal/cmd/genoptions/gen.sh
index fab1f9d3..d37649b6 100755
--- a/internal/cmd/genoptions/gen.sh
+++ b/internal/cmd/genoptions/gen.sh
@@ -12,6 +12,7 @@ go build -o genoptions main.go
 popd
 
 ./internal/cmd/genoptions/genoptions -objects=jwe/options.yaml
+./internal/cmd/genoptions/genoptions -objects=jwk/options.yaml
 ./internal/cmd/genoptions/genoptions -objects=jws/options.yaml
 ./internal/cmd/genoptions/genoptions -objects=jwt/options.yaml
 
diff --git a/internal/cmd/genoptions/main.go b/internal/cmd/genoptions/main.go
index fe8ceeda..75f6a8a1 100644
--- a/internal/cmd/genoptions/main.go
+++ b/internal/cmd/genoptions/main.go
@@ -119,6 +119,16 @@ func genOptions(objects *Objects) error {
 
 	o.LL(`package %s`, objects.PackageName)
 
+	// Write all imports -- they will be pruned by golang.org/x/tools/imports eventually,
+	// so it's okay to be redundant
+	o.WriteImports(
+		`github.com/lestrrat-go/jwx/v2/jwa`,
+		`github.com/lestrrat-go/jwx/v2/jwe`,
+		`github.com/lestrrat-go/jwx/v2/jwk`,
+		`github.com/lestrrat-go/jwx/v2/jws`,
+		`github.com/lestrrat-go/jwx/v2/jwt`,
+	)
+
 	o.LL(`type Option = option.Interface`)
 
 	for _, iface := range objects.Interfaces {
diff --git a/jwk/jwk.go b/jwk/jwk.go
index 75071350..c8eb65dd 100644
--- a/jwk/jwk.go
+++ b/jwk/jwk.go
@@ -588,7 +588,7 @@ func ParseString(s string, options ...ParseOption) (Set, error) {
 // AssignKeyID is a convenience function to automatically assign the "kid"
 // section of the key, if it already doesn't have one. It uses Key.Thumbprint
 // method with crypto.SHA256 as the default hashing algorithm
-func AssignKeyID(key Key, options ...Option) error {
+func AssignKeyID(key Key, options ...AssignKeyIDOption) error {
 	if _, ok := key.Get(KeyIDKey); ok {
 		return nil
 	}
diff --git a/jwk/options.go b/jwk/options.go
new file mode 100644
index 00000000..98fcc409
--- /dev/null
+++ b/jwk/options.go
@@ -0,0 +1,38 @@
+package jwk
+
+import (
+	"github.com/lestrrat-go/option"
+)
+
+type identTypedField struct{}
+
+type typedFieldPair struct {
+	Name  string
+	Value interface{}
+}
+
+// WithTypedField allows a private field to be parsed into the object type of
+// your choice. It works much like the RegisterCustomField, but the effect
+// is only applicable to the jwt.Parse function call which receives this option.
+//
+// While this can be extremely useful, this option should be used with caution:
+// There are many caveats that your entire team/user-base needs to be aware of,
+// and therefore in general its use is discouraged. Only use it when you know
+// what you are doing, and you document its use clearly for others.
+//
+// First and foremost, this is a "per-object" option. Meaning that given the same
+// serialized format, it is possible to generate two objects whose internal
+// representations may differ. That is, if you parse one _WITH_ the option,
+// and the other _WITHOUT_, their internal representation may completely differ.
+// This could potentially lead to problems.
+//
+// Second, specifying this option will slightly slow down the decoding process
+// as it needs to consult multiple definitions sources (global and local), so
+// be careful if you are decoding a large number of tokens, as the effects will stack up.
+func WithTypedField(name string, object interface{}) ParseOption {
+	return &parseOption{
+		option.New(identTypedField{},
+			typedFieldPair{Name: name, Value: object},
+		),
+	}
+}
diff --git a/jwk/options.yaml b/jwk/options.yaml
new file mode 100644
index 00000000..ae84ade5
--- /dev/null
+++ b/jwk/options.yaml
@@ -0,0 +1,117 @@
+package_name: jwk
+output: jwk/options_gen.go
+interfaces:
+  - name: AutoRefreshOption
+    comment: |
+      AutoRefreshOption is a type of Option that can be passed to the
+      AutoRefresh object.
+  - name: AssignKeyIDOption
+  - name: FetchOption
+    methods:
+      - autoRefreshOption
+      - fetchOption
+    comment: |
+      FetchOption is a type of Option that can be passed to `jwk.Fetch()`
+      FetchOption also implements the `AutoRefreshOption`, and thus can
+      safely be passed to `(*jwk.AutoRefresh).Configure()`
+  - name: ParseOption
+    methods:
+      - autoRefreshOption
+      - fetchOption
+      - readFileOption
+    comment: |
+      ParseOption is a type of Option that can be passed to `jwk.Parse()`
+      ParseOption also implmentsthe `ReadFileOPtion` and `AutoRefreshOption`,
+      and thus safely be passed to `jwk.ReadFile` and `(*jwk.AutoRefresh).Configure()`
+options:
+  - ident: HTTPClient
+    interface: FetchOption
+    argument_type: HTTPClient
+    comment: |
+      WithHTTPClient allows users to specify the "net/http".Client object that
+      is used when fetching jwk.Set objects.
+  - ident: FetchBackoff
+    interface: FetchOption
+    argument_type: backoff.Policy
+    comment: |
+      WithFetchBackoff specifies the backoff policy to use when
+      refreshing a JWKS from a remote server fails.
+      
+      This does not have any effect on initial `Fetch()`, or any of the `Refresh()` calls --
+      the backoff is applied ONLY on the background refreshing goroutine.
+  - ident: ThumbprintHash
+    interface: AssignKeyIDOption
+    argument_type: crypto.Hash
+  - ident: RefreshInterval
+    interface: AutoRefreshOption
+    argument_type: time.Duration
+    comment: |
+      WithRefreshInterval specifies the static interval between refreshes
+      of jwk.Set objects controlled by jwk.AutoRefresh.
+      
+      Providing this option overrides the adaptive token refreshing based
+      on Cache-Control/Expires header (and jwk.WithMinRefreshInterval),
+      and refreshes will *always* happen in this interval.
+  - ident: MinRefreshInterval
+    interface: AutoRefreshOption
+    argument_type: time.Duration
+    comment: |
+      WithMinRefreshInterval specifies the minimum refresh interval to be used
+      when using AutoRefresh. This value is ONLY used if you did not specify
+      a user-supplied static refresh interval via `WithRefreshInterval`.
+      
+      This value is used as a fallback value when tokens are refreshed.
+      
+      When we fetch the key from a remote URL, we first look at the max-age
+      directive from Cache-Control response header. If this value is present,
+      we compare the max-age value and the value specified by this option
+      and take the larger one.
+      
+      Next we check for the Expires header, and similarly if the header is
+      present, we compare it against the value specified by this option,
+      and take the larger one.
+      
+      Finally, if neither of the above headers are present, we use the
+      value specified by this option as the next refresh timing
+      
+      If unspecified, the minimum refresh interval is 1 hour
+  - ident: LocalRegistry
+    option_name: withLocalRegistry
+    interface: ParseOption
+    argument_type: '*json.Registry'
+    comment: This option is only available for internal code. Users don't get to play with it
+  - ident: PEM
+    interface: ParseOption
+    argument_type: bool
+    comment: WithPEM specifies that the input to `Parse()` is a PEM encoded key.
+  - ident: FetchWhitelist
+    interface: FetchOption
+    argument_type: Whitelist
+    comment: |
+      WithFetchWhitelist specifies the Whitelist object to use when
+      fetching JWKs from a remote source. This option can be passed
+      to both `jwk.Fetch()`, `jwk.NewAutoRefresh()`, and `(*jwk.AutoRefresh).Configure()`
+  - ident: IgnoreParseError
+    interface: ParseOption
+    argument_type: bool
+    comment: |
+      WithIgnoreParseError is only applicable when used with `jwk.Parse()`
+      (i.e. to parse JWK sets). If passed to `jwk.ParseKey()`, the function
+      will return an error no matter what the input is.
+      
+      DO NOT USE WITHOUT EXHAUSTING ALL OTHER ROUTES FIRST.
+      
+      The option specifies that errors found during parsing of individual
+      keys are ignored. For example, if you had keys A, B, C where B is
+      invalid (e.g. it does not contain the required fields), then the
+      resulting JWKS will contain keys A and C only.
+      
+      This options exists as an escape hatch for those times when a
+      key in a JWKS that is irrelevant for your use case is causing
+      your JWKS parsing to fail, and you want to get to the rest of the
+      keys in the JWKS.
+      
+      Again, DO NOT USE unless you have exhausted all other routes.
+      When you use this option, you will not be able to tell if you are
+      using a faulty JWKS, except for when there are JSON syntax errors.
+
diff --git a/jwk/option.go b/jwk/options_gen.go
similarity index 64%
rename from jwk/option.go
rename to jwk/options_gen.go
index 6fcabf97..368ef50a 100644
--- a/jwk/option.go
+++ b/jwk/options_gen.go
@@ -1,3 +1,5 @@
+// This file is auto-generated by internal/cmd/genoptions/main.go. DO NOT EDIT
+
 package jwk
 
 import (
@@ -11,16 +13,16 @@ import (
 
 type Option = option.Interface
 
-type identHTTPClient struct{}
-type identThumbprintHash struct{}
-type identRefreshInterval struct{}
-type identMinRefreshInterval struct{}
-type identFetchBackoff struct{}
-type identPEM struct{}
-type identTypedField struct{}
-type identLocalRegistry struct{}
-type identFetchWhitelist struct{}
-type identIgnoreParseError struct{}
+type AssignKeyIDOption interface {
+	Option
+	assignKeyIDOption()
+}
+
+type assignKeyIDOption struct {
+	Option
+}
+
+func (*assignKeyIDOption) assignKeyIDOption() {}
 
 // AutoRefreshOption is a type of Option that can be passed to the
 // AutoRefresh object.
@@ -39,7 +41,8 @@ func (*autoRefreshOption) autoRefreshOption() {}
 // FetchOption also implements the `AutoRefreshOption`, and thus can
 // safely be passed to `(*jwk.AutoRefresh).Configure()`
 type FetchOption interface {
-	AutoRefreshOption
+	Option
+	autoRefreshOption()
 	fetchOption()
 }
 
@@ -48,15 +51,17 @@ type fetchOption struct {
 }
 
 func (*fetchOption) autoRefreshOption() {}
-func (*fetchOption) fetchOption()       {}
+
+func (*fetchOption) fetchOption() {}
 
 // ParseOption is a type of Option that can be passed to `jwk.Parse()`
 // ParseOption also implmentsthe `ReadFileOPtion` and `AutoRefreshOption`,
 // and thus safely be passed to `jwk.ReadFile` and `(*jwk.AutoRefresh).Configure()`
 type ParseOption interface {
-	ReadFileOption
-	AutoRefreshOption
-	parseOption()
+	Option
+	autoRefreshOption()
+	fetchOption()
+	readFileOption()
 }
 
 type parseOption struct {
@@ -64,13 +69,55 @@ type parseOption struct {
 }
 
 func (*parseOption) autoRefreshOption() {}
-func (*parseOption) parseOption()       {}
-func (*parseOption) readFileOption()    {}
 
-// WithHTTPClient allows users to specify the "net/http".Client object that
-// is used when fetching jwk.Set objects.
-func WithHTTPClient(cl HTTPClient) FetchOption {
-	return &fetchOption{option.New(identHTTPClient{}, cl)}
+func (*parseOption) fetchOption() {}
+
+func (*parseOption) readFileOption() {}
+
+type identFetchBackoff struct{}
+type identFetchWhitelist struct{}
+type identHTTPClient struct{}
+type identIgnoreParseError struct{}
+type identLocalRegistry struct{}
+type identMinRefreshInterval struct{}
+type identPEM struct{}
+type identRefreshInterval struct{}
+type identThumbprintHash struct{}
+
+func (identFetchBackoff) String() string {
+	return "WithFetchBackoff"
+}
+
+func (identFetchWhitelist) String() string {
+	return "WithFetchWhitelist"
+}
+
+func (identHTTPClient) String() string {
+	return "WithHTTPClient"
+}
+
+func (identIgnoreParseError) String() string {
+	return "WithIgnoreParseError"
+}
+
+func (identLocalRegistry) String() string {
+	return "withLocalRegistry"
+}
+
+func (identMinRefreshInterval) String() string {
+	return "WithMinRefreshInterval"
+}
+
+func (identPEM) String() string {
+	return "WithPEM"
+}
+
+func (identRefreshInterval) String() string {
+	return "WithRefreshInterval"
+}
+
+func (identThumbprintHash) String() string {
+	return "WithThumbprintHash"
 }
 
 // WithFetchBackoff specifies the backoff policy to use when
@@ -82,20 +129,45 @@ func WithFetchBackoff(v backoff.Policy) FetchOption {
 	return &fetchOption{option.New(identFetchBackoff{}, v)}
 }
 
-func WithThumbprintHash(h crypto.Hash) Option {
-	return option.New(identThumbprintHash{}, h)
+// WithFetchWhitelist specifies the Whitelist object to use when
+// fetching JWKs from a remote source. This option can be passed
+// to both `jwk.Fetch()`, `jwk.NewAutoRefresh()`, and `(*jwk.AutoRefresh).Configure()`
+func WithFetchWhitelist(v Whitelist) FetchOption {
+	return &fetchOption{option.New(identFetchWhitelist{}, v)}
 }
 
-// WithRefreshInterval specifies the static interval between refreshes
-// of jwk.Set objects controlled by jwk.AutoRefresh.
+// WithHTTPClient allows users to specify the "net/http".Client object that
+// is used when fetching jwk.Set objects.
+func WithHTTPClient(v HTTPClient) FetchOption {
+	return &fetchOption{option.New(identHTTPClient{}, v)}
+}
+
+// WithIgnoreParseError is only applicable when used with `jwk.Parse()`
+// (i.e. to parse JWK sets). If passed to `jwk.ParseKey()`, the function
+// will return an error no matter what the input is.
 //
-// Providing this option overrides the adaptive token refreshing based
-// on Cache-Control/Expires header (and jwk.WithMinRefreshInterval),
-// and refreshes will *always* happen in this interval.
-func WithRefreshInterval(d time.Duration) AutoRefreshOption {
-	return &autoRefreshOption{
-		option.New(identRefreshInterval{}, d),
-	}
+// DO NOT USE WITHOUT EXHAUSTING ALL OTHER ROUTES FIRST.
+//
+// The option specifies that errors found during parsing of individual
+// keys are ignored. For example, if you had keys A, B, C where B is
+// invalid (e.g. it does not contain the required fields), then the
+// resulting JWKS will contain keys A and C only.
+//
+// This options exists as an escape hatch for those times when a
+// key in a JWKS that is irrelevant for your use case is causing
+// your JWKS parsing to fail, and you want to get to the rest of the
+// keys in the JWKS.
+//
+// Again, DO NOT USE unless you have exhausted all other routes.
+// When you use this option, you will not be able to tell if you are
+// using a faulty JWKS, except for when there are JSON syntax errors.
+func WithIgnoreParseError(v bool) ParseOption {
+	return &parseOption{option.New(identIgnoreParseError{}, v)}
+}
+
+// This option is only available for internal code. Users don't get to play with it
+func withLocalRegistry(v *json.Registry) ParseOption {
+	return &parseOption{option.New(identLocalRegistry{}, v)}
 }
 
 // WithMinRefreshInterval specifies the minimum refresh interval to be used
@@ -117,81 +189,25 @@ func WithRefreshInterval(d time.Duration) AutoRefreshOption {
 // value specified by this option as the next refresh timing
 //
 // If unspecified, the minimum refresh interval is 1 hour
-func WithMinRefreshInterval(d time.Duration) AutoRefreshOption {
-	return &autoRefreshOption{
-		option.New(identMinRefreshInterval{}, d),
-	}
+func WithMinRefreshInterval(v time.Duration) AutoRefreshOption {
+	return &autoRefreshOption{option.New(identMinRefreshInterval{}, v)}
 }
 
 // WithPEM specifies that the input to `Parse()` is a PEM encoded key.
 func WithPEM(v bool) ParseOption {
-	return &parseOption{
-		option.New(identPEM{}, v),
-	}
-}
-
-type typedFieldPair struct {
-	Name  string
-	Value interface{}
+	return &parseOption{option.New(identPEM{}, v)}
 }
 
-// WithTypedField allows a private field to be parsed into the object type of
-// your choice. It works much like the RegisterCustomField, but the effect
-// is only applicable to the jwt.Parse function call which receives this option.
-//
-// While this can be extremely useful, this option should be used with caution:
-// There are many caveats that your entire team/user-base needs to be aware of,
-// and therefore in general its use is discouraged. Only use it when you know
-// what you are doing, and you document its use clearly for others.
-//
-// First and foremost, this is a "per-object" option. Meaning that given the same
-// serialized format, it is possible to generate two objects whose internal
-// representations may differ. That is, if you parse one _WITH_ the option,
-// and the other _WITHOUT_, their internal representation may completely differ.
-// This could potentially lead to problems.
+// WithRefreshInterval specifies the static interval between refreshes
+// of jwk.Set objects controlled by jwk.AutoRefresh.
 //
-// Second, specifying this option will slightly slow down the decoding process
-// as it needs to consult multiple definitions sources (global and local), so
-// be careful if you are decoding a large number of tokens, as the effects will stack up.
-func WithTypedField(name string, object interface{}) ParseOption {
-	return &parseOption{
-		option.New(identTypedField{},
-			typedFieldPair{Name: name, Value: object},
-		),
-	}
-}
-
-// This option is only available for internal code. Users don't get to play with it
-func withLocalRegistry(r *json.Registry) ParseOption {
-	return &parseOption{option.New(identLocalRegistry{}, r)}
-}
-
-// WithFetchWhitelist specifies the Whitelist object to use when
-// fetching JWKs from a remote source. This option can be passed
-// to both `jwk.Fetch()`, `jwk.NewAutoRefresh()`, and `(*jwk.AutoRefresh).Configure()`
-func WithFetchWhitelist(w Whitelist) FetchOption {
-	return &fetchOption{option.New(identFetchWhitelist{}, w)}
+// Providing this option overrides the adaptive token refreshing based
+// on Cache-Control/Expires header (and jwk.WithMinRefreshInterval),
+// and refreshes will *always* happen in this interval.
+func WithRefreshInterval(v time.Duration) AutoRefreshOption {
+	return &autoRefreshOption{option.New(identRefreshInterval{}, v)}
 }
 
-// WithIgnoreParseError is only applicable when used with `jwk.Parse()`
-// (i.e. to parse JWK sets). If passed to `jwk.ParseKey()`, the function
-// will return an error no matter what the input is.
-//
-// DO NOT USE WITHOUT EXHAUSTING ALL OTHER ROUTES FIRST.
-//
-// The option specifies that errors found during parsing of individual
-// keys are ignored. For example, if you had keys A, B, C where B is
-// invalid (e.g. it does not contain the required fields), then the
-// resulting JWKS will contain keys A and C only.
-//
-// This options exists as an escape hatch for those times when a
-// key in a JWKS that is irrelevant for your use case is causing
-// your JWKS parsing to fail, and you want to get to the rest of the
-// keys in the JWKS.
-//
-// Again, DO NOT USE unless you have exhausted all other routes.
-// When you use this option, you will not be able to tell if you are
-// using a faulty JWKS, except for when there are JSON syntax errors.
-func WithIgnoreParseError(b bool) ParseOption {
-	return &parseOption{option.New(identIgnoreParseError{}, b)}
+func WithThumbprintHash(v crypto.Hash) AssignKeyIDOption {
+	return &assignKeyIDOption{option.New(identThumbprintHash{}, v)}
 }


Test patch:
diff --git a/jwk/options_gen_test.go b/jwk/options_gen_test.go
new file mode 100644
index 00000000..1b98c80d
--- /dev/null
+++ b/jwk/options_gen_test.go
@@ -0,0 +1,21 @@
+// This file is auto-generated by internal/cmd/genoptions/main.go. DO NOT EDIT
+
+package jwk
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestOptionIdent(t *testing.T) {
+	require.Equal(t, "WithFetchBackoff", identFetchBackoff{}.String())
+	require.Equal(t, "WithFetchWhitelist", identFetchWhitelist{}.String())
+	require.Equal(t, "WithHTTPClient", identHTTPClient{}.String())
+	require.Equal(t, "WithIgnoreParseError", identIgnoreParseError{}.String())
+	require.Equal(t, "withLocalRegistry", identLocalRegistry{}.String())
+	require.Equal(t, "WithMinRefreshInterval", identMinRefreshInterval{}.String())
+	require.Equal(t, "WithPEM", identPEM{}.String())
+	require.Equal(t, "WithRefreshInterval", identRefreshInterval{}.String())
+	require.Equal(t, "WithThumbprintHash", identThumbprintHash{}.String())
+}