| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- package jwk
- import (
- "crypto"
- "time"
- "github.com/lestrrat-go/backoff/v2"
- "github.com/lestrrat-go/jwx/internal/json"
- "github.com/lestrrat-go/option"
- )
- 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{}
- // AutoRefreshOption is a type of Option that can be passed to the
- // AutoRefresh object.
- type AutoRefreshOption interface {
- Option
- autoRefreshOption()
- }
- type autoRefreshOption struct {
- Option
- }
- func (*autoRefreshOption) autoRefreshOption() {}
- // 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()`
- type FetchOption interface {
- AutoRefreshOption
- fetchOption()
- }
- type fetchOption struct {
- Option
- }
- func (*fetchOption) autoRefreshOption() {}
- 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()
- }
- type parseOption struct {
- Option
- }
- 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)}
- }
- // 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.
- func WithFetchBackoff(v backoff.Policy) FetchOption {
- return &fetchOption{option.New(identFetchBackoff{}, v)}
- }
- func WithThumbprintHash(h crypto.Hash) Option {
- return option.New(identThumbprintHash{}, h)
- }
- // 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.
- func WithRefreshInterval(d time.Duration) AutoRefreshOption {
- return &autoRefreshOption{
- option.New(identRefreshInterval{}, d),
- }
- }
- // 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
- func WithMinRefreshInterval(d time.Duration) AutoRefreshOption {
- return &autoRefreshOption{
- option.New(identMinRefreshInterval{}, d),
- }
- }
- // 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{}
- }
- // 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},
- ),
- }
- }
- // 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)}
- }
- // 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)}
- }
|