Documentation ¶
Overview ¶
Package jwk implements JWK as described in https://tools.ietf.org/html/rfc7517
Index ¶
- Constants
- func AssignKeyID(key Key, options ...Option) error
- func ParseRawKey(data []byte, rawkey interface{}) error
- func Pem(v interface{}) ([]byte, error)
- func PublicRawKeyOf(v interface{}) (interface{}, error)
- func RegisterCustomField(name string, object interface{})
- type AutoRefresh
- func (af *AutoRefresh) Configure(url string, options ...AutoRefreshOption)
- func (af *AutoRefresh) ErrorSink(ch chan AutoRefreshError)
- func (af *AutoRefresh) Fetch(ctx context.Context, url string) (Set, error)
- func (af *AutoRefresh) Refresh(ctx context.Context, url string) (Set, error)
- func (af *AutoRefresh) Snapshot() <-chan TargetSnapshot
- type AutoRefreshError
- type AutoRefreshOption
- type CertificateChain
- type DecodeCtx
- type ECDSAPrivateKey
- type ECDSAPublicKey
- type FetchOption
- type HTTPClient
- type HeaderIterator
- type HeaderPair
- type HeaderVisitor
- type HeaderVisitorFunc
- type Key
- type KeyIterator
- type KeyOperation
- type KeyOperationList
- type KeyPair
- type KeyUsageType
- type KeyWithDecodeCtx
- type OKPPrivateKey
- type OKPPublicKey
- type Option
- type ParseOption
- type PublicKeyer
- type RSAPrivateKey
- type RSAPublicKey
- type ReadFileOption
- type Set
- func Fetch(ctx context.Context, urlstring string, options ...FetchOption) (Set, error)
- func NewSet() Set
- func Parse(src []byte, options ...ParseOption) (Set, error)
- func ParseReader(src io.Reader, options ...ParseOption) (Set, error)
- func ParseString(s string, options ...ParseOption) (Set, error)
- func PublicSetOf(v Set) (Set, error)
- func ReadFile(path string, options ...ReadFileOption) (Set, error)
- type SymmetricKey
- type TargetSnapshot
Constants ¶
const ( ECDSACrvKey = "crv" ECDSADKey = "d" ECDSAXKey = "x" ECDSAYKey = "y" )
const ( KeyTypeKey = "kty" KeyUsageKey = "use" KeyOpsKey = "keyOps" AlgorithmKey = "alg" KeyIDKey = "kid" X509URLKey = "x58" X509CertChainKey = "x5c" X509CertThumbprintKey = "x5t" X509CertThumbprintS256Key = "x5t#S256" )
const ( OKPCrvKey = "crv" OKPDKey = "d" OKPXKey = "x" )
const ( RSADKey = "d" RSADPKey = "dp" RSADQKey = "dq" RSAEKey = "e" RSANKey = "n" RSAPKey = "p" RSAQIKey = "qi" RSAQKey = "q" )
const (
SymmetricOctetsKey = "k"
)
Variables ¶
This section is empty.
Functions ¶
func AssignKeyID ¶ added in v1.0.2
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 ParseRawKey ¶ added in v1.0.6
ParseRawKey is a combination of ParseKey and Raw. It parses a single JWK key, and assigns the "raw" key to the given parameter. The key must either be a pointer to an empty interface, or a pointer to the actual raw key type such as *rsa.PrivateKey, *ecdsa.PublicKey, *[]byte, etc.
func Pem ¶ added in v1.1.1
Pem serializes the given jwk.Key in PEM encoded ASN.1 DER format, using either PKCS8 for private keys and PKIX for public keys. If you need to encode using PKCS1 or SEC1, you must do it yourself.
Argument must be of type jwk.Key or jwk.Set ¶
Currently only EC (including Ed25519) and RSA keys (and jwk.Set comprised of these key types) are supported.
func PublicRawKeyOf ¶ added in v1.1.0
func PublicRawKeyOf(v interface{}) (interface{}, error)
PublicRawKeyOf returns the corresponding public key of the given value `v` (e.g. given *rsa.PrivateKey, *rsa.PublicKey is returned) If `v` is already a public key, the key itself is returned.
The returned value will always be a pointer to the public key, except when a []byte (e.g. symmetric key, ed25519 key) is passed to `v`. In this case, the same []byte value is returned.
func RegisterCustomField ¶ added in v1.1.2
func RegisterCustomField(name string, object interface{})
RegisterCustomField allows users to specify that a private field be decoded as an instance of the specified type. This option has a global effect.
For example, suppose you have a custom field `x-birthday`, which you want to represent as a string formatted in RFC3339 in JSON, but want it back as `time.Time`.
In that case you would register a custom field as follows
jwk.RegisterCustomField(`x-birthday`, timeT)
Then `key.Get("x-birthday")` will still return an `interface{}`, but you can convert its type to `time.Time`
bdayif, _ := key.Get(`x-birthday`) bday := bdayif.(time.Time)
Types ¶
type AutoRefresh ¶ added in v1.0.7
type AutoRefresh struct {
// contains filtered or unexported fields
}
AutoRefresh is a container that keeps track of jwk.Set object by their source URLs. The jwk.Set objects are refreshed automatically behind the scenes.
Before retrieving the jwk.Set objects, the user must pre-register the URLs they intend to use by calling `Configure()`
ar := jwk.NewAutoRefresh(ctx) ar.Configure(url, options...)
Once registered, you can call `Fetch()` to retrieve the jwk.Set object.
All JWKS objects that are retrieved via the auto-fetch mechanism should be treated read-only, as they are shared among the consumers and this object.
func NewAutoRefresh ¶ added in v1.0.7
func NewAutoRefresh(ctx context.Context) *AutoRefresh
NewAutoRefresh creates a container that keeps track of JWKS objects which are automatically refreshed.
The context object in the argument controls the life-span of the auto-refresh worker. If you are using this in a long running process, this should mostly be set to a context that ends when the main loop/part of your program exits:
func MainLoop() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() ar := jwk.AutoRefresh(ctx) for ... { ... } }
func (*AutoRefresh) Configure ¶ added in v1.0.7
func (af *AutoRefresh) Configure(url string, options ...AutoRefreshOption)
Configure registers the url to be controlled by AutoRefresh, and also sets any options associated to it.
Note that options are treated as a whole -- you can't just update one value. For example, if you did:
ar.Configure(url, jwk.WithHTTPClient(...)) ar.Configure(url, jwk.WithRefreshInterval(...))
The the end result is that `url` is ONLY associated with the options given in the second call to `Configure()`, i.e. `jwk.WithRefreshInterval`. The other unspecified options, including the HTTP client, is set to their default values.
Configuration must propagate between goroutines, and therefore are not atomic (But changes should be felt "soon enough" for practical purposes)
func (*AutoRefresh) ErrorSink ¶ added in v1.2.5
func (af *AutoRefresh) ErrorSink(ch chan AutoRefreshError)
ErrorSink sets a channel to receive JWK fetch errors, if any. Only the errors that occurred *after* the channel was set will be sent.
The user is responsible for properly draining the channel. If the channel is not drained properly, errors will be discarded.
To disable, set a nil channel.
func (*AutoRefresh) Fetch ¶ added in v1.0.7
Fetch returns a jwk.Set from the given url.
If it has previously been fetched, then a cached value is returned.
If this the first time `url` was requested, an HTTP request will be sent, synchronously.
When accessed via multiple goroutines concurrently, and the cache has not been populated yet, only the first goroutine is allowed to perform the initialization (HTTP fetch and cache population). All other goroutines will be blocked until the operation is completed.
DO NOT modify the jwk.Set object returned by this method, as the objects are shared among all consumers and the backend goroutine
func (*AutoRefresh) Refresh ¶ added in v1.0.7
Refresh is the same as Fetch(), except that HTTP fetching is done synchronously.
This is useful when you want to force an HTTP fetch instead of waiting for the background goroutine to do it, for example when you want to make sure the AutoRefresh cache is warmed up before starting your main loop
func (*AutoRefresh) Snapshot ¶ added in v1.0.7
func (af *AutoRefresh) Snapshot() <-chan TargetSnapshot
type AutoRefreshError ¶ added in v1.2.5
type AutoRefreshOption ¶ added in v1.0.7
type AutoRefreshOption interface { Option // contains filtered or unexported methods }
AutoRefreshOption is a type of Option that can be passed to the AutoRefresh object.
func WithMinRefreshInterval ¶ added in v1.0.7
func WithMinRefreshInterval(d time.Duration) AutoRefreshOption
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 WithRefreshInterval ¶ added in v1.0.7
func WithRefreshInterval(d time.Duration) AutoRefreshOption
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.
type CertificateChain ¶
type CertificateChain struct {
// contains filtered or unexported fields
}
func (*CertificateChain) Accept ¶
func (c *CertificateChain) Accept(v interface{}) error
func (CertificateChain) Get ¶
func (c CertificateChain) Get() []*x509.Certificate
func (CertificateChain) MarshalJSON ¶ added in v1.0.0
func (c CertificateChain) MarshalJSON() ([]byte, error)
func (*CertificateChain) UnmarshalJSON ¶ added in v1.0.0
func (c *CertificateChain) UnmarshalJSON(buf []byte) error
type ECDSAPrivateKey ¶
type ECDSAPrivateKey interface { Key FromRaw(*ecdsa.PrivateKey) error Crv() jwa.EllipticCurveAlgorithm D() []byte X() []byte Y() []byte }
func NewECDSAPrivateKey ¶ added in v1.0.0
func NewECDSAPrivateKey() ECDSAPrivateKey
type ECDSAPublicKey ¶
type ECDSAPublicKey interface { Key FromRaw(*ecdsa.PublicKey) error Crv() jwa.EllipticCurveAlgorithm X() []byte Y() []byte }
func NewECDSAPublicKey ¶ added in v1.0.0
func NewECDSAPublicKey() ECDSAPublicKey
type FetchOption ¶ added in v1.1.0
type FetchOption interface { AutoRefreshOption // contains filtered or unexported methods }
FetchOption is a type of Option that can be passed to `jwk.Fetch()` This type also implements the `AutoRefreshOption`, and thus can be safely passed to `(*jwk.AutoRefresh).Configure()`
func WithFetchBackoff ¶ added in v1.1.0
func WithFetchBackoff(v backoff.Policy) FetchOption
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 WithHTTPClient ¶
func WithHTTPClient(cl HTTPClient) FetchOption
WithHTTPClient allows users to specify the "net/http".Client object that is used when fetching jwk.Set objects.
type HTTPClient ¶
HTTPClient specifies the minimum interface that is required for our JWK fetching tools.
type HeaderIterator ¶ added in v1.0.0
type HeaderPair ¶ added in v1.0.0
type HeaderVisitor ¶ added in v1.0.0
type HeaderVisitor = iter.MapVisitor
type HeaderVisitorFunc ¶ added in v1.0.0
type HeaderVisitorFunc = iter.MapVisitorFunc
type Key ¶
type Key interface { // Get returns the value of a single field. The second boolean return value // will be false if the field is not stored in the source // // This method, which returns an `interface{}`, exists because // these objects can contain extra _arbitrary_ fields that users can // specify, and there is no way of knowing what type they could be Get(string) (interface{}, bool) // Set sets the value of a single field. Note that certain fields, // notably "kty", cannot be altered, but will not return an error // // This method, which takes an `interface{}`, exists because // these objects can contain extra _arbitrary_ fields that users can // specify, and there is no way of knowing what type they could be Set(string, interface{}) error // Remove removes the field associated with the specified key. // There is no way to remove the `kty` (key type). You will ALWAYS be left with one field in a jwk.Key. Remove(string) error // Raw creates the corresponding raw key. For example, // EC types would create *ecdsa.PublicKey or *ecdsa.PrivateKey, // and OctetSeq types create a []byte key. // // If you do not know the exact type of a jwk.Key before attempting // to obtain the raw key, you can simply pass a pointer to an // empty interface as the first argument. // // If you already know the exact type, it is recommended that you // pass a pointer to the zero value of the actual key type (e.g. &rsa.PrivateKey) // for efficiency. Raw(interface{}) error // Thumbprint returns the JWK thumbprint using the indicated // hashing algorithm, according to RFC 7638 Thumbprint(crypto.Hash) ([]byte, error) // Iterate returns an iterator that returns all keys and values. // See github.com/lestrrat-go/iter for a description of the iterator. Iterate(ctx context.Context) HeaderIterator // Walk is a utility tool that allows a visitor to iterate all keys and values Walk(context.Context, HeaderVisitor) error // AsMap is a utility tool that returns a new map that contains the same fields as the source AsMap(context.Context) (map[string]interface{}, error) // PrivateParams returns the non-standard elements in the source structure // WARNING: DO NOT USE PrivateParams() IF YOU HAVE CONCURRENT CODE ACCESSING THEM. // Use `AsMap()` to get a copy of the entire header, or use `Iterate()` instead PrivateParams() map[string]interface{} // Clone creates a new instance of the same type Clone() (Key, error) KeyType() jwa.KeyType // PublicKey creates the corresponding PublicKey type for this object. // All fields are copied onto the new public key, except for those that are not allowed. // // If the key is already a public key, it returns a new copy minus the disallowed fields as above. PublicKey() (Key, error) KeyUsage() string KeyOps() KeyOperationList Algorithm() string KeyID() string X509URL() string X509CertChain() []*x509.Certificate X509CertThumbprint() string X509CertThumbprintS256() string // contains filtered or unexported methods }
Key defines the minimal interface for each of the key types. Their use and implementation differ significantly between each key types, so you should use type assertions to perform more specific tasks with each key
func New ¶
New creates a jwk.Key from the given key (RSA/ECDSA/symmetric keys).
The constructor auto-detects the type of key to be instantiated based on the input type:
- "crypto/rsa".PrivateKey and "crypto/rsa".PublicKey creates an RSA based key
- "crypto/ecdsa".PrivateKey and "crypto/ecdsa".PublicKey creates an EC based key
- "crypto/ed25519".PrivateKey and "crypto/ed25519".PublicKey creates an OKP based key
- []byte creates a symmetric key
func ParseKey ¶ added in v1.0.0
func ParseKey(data []byte, options ...ParseOption) (Key, error)
ParseKey parses a single key JWK. Unlike `jwk.Parse` this method will report failure if you attempt to pass a JWK set. Only use this function when you know that the data is a single JWK.
Given a WithPEM(true) option, this function assumes that the given input is PEM encoded ASN.1 DER format key.
Note that a successful parsing of any type of key does NOT necessarily guarantee a valid key. For example, no checks against expiration dates are performed for certificate expiration, no checks against missing parameters are performed, etc.
func PublicKeyOf ¶ added in v1.0.0
PublicKeyOf returns the corresponding public version of the jwk.Key. If `v` is a SymmetricKey, then the same value is returned. If `v` is already a public key, the key itself is returned.
If `v` is a private key type that has a `PublicKey()` method, be aware that all fields will be copied onto the new public key. It is the caller's responsibility to remove any fields, if necessary
If `v` is a raw key, the key is first converted to a `jwk.Key`
type KeyIterator ¶ added in v1.0.0
type KeyOperation ¶
type KeyOperation string
const ( KeyOpSign KeyOperation = "sign" // (compute digital signature or MAC) KeyOpVerify KeyOperation = "verify" // (verify digital signature or MAC) KeyOpEncrypt KeyOperation = "encrypt" // (encrypt content) KeyOpDecrypt KeyOperation = "decrypt" // (decrypt content and validate decryption, if applicable) KeyOpWrapKey KeyOperation = "wrapKey" // (encrypt key) KeyOpUnwrapKey KeyOperation = "unwrapKey" // (decrypt key and validate decryption, if applicable) KeyOpDeriveKey KeyOperation = "deriveKey" // (derive key) KeyOpDeriveBits KeyOperation = "deriveBits" // (derive bits not to be used as a key) )
type KeyOperationList ¶
type KeyOperationList []KeyOperation
func (*KeyOperationList) Accept ¶
func (ops *KeyOperationList) Accept(v interface{}) error
func (*KeyOperationList) Get ¶
func (ops *KeyOperationList) Get() KeyOperationList
type KeyUsageType ¶
type KeyUsageType string
KeyUsageType is used to denote what this key should be used for
const ( // ForSignature is the value used in the headers to indicate that // this key should be used for signatures ForSignature KeyUsageType = "sig" // ForEncryption is the value used in the headers to indicate that // this key should be used for encrypting ForEncryption KeyUsageType = "enc" )
func (*KeyUsageType) Accept ¶ added in v1.0.7
func (k *KeyUsageType) Accept(v interface{}) error
func (KeyUsageType) String ¶ added in v1.0.7
func (k KeyUsageType) String() string
type KeyWithDecodeCtx ¶ added in v1.2.1
type KeyWithDecodeCtx = json.DecodeCtxContainer
type OKPPrivateKey ¶ added in v1.0.7
type OKPPrivateKey interface { Key FromRaw(interface{}) error Crv() jwa.EllipticCurveAlgorithm D() []byte X() []byte }
func NewOKPPrivateKey ¶ added in v1.0.7
func NewOKPPrivateKey() OKPPrivateKey
type OKPPublicKey ¶ added in v1.0.7
type OKPPublicKey interface { Key FromRaw(interface{}) error Crv() jwa.EllipticCurveAlgorithm X() []byte }
func NewOKPPublicKey ¶ added in v1.0.7
func NewOKPPublicKey() OKPPublicKey
type Option ¶
func WithThumbprintHash ¶ added in v1.0.2
type ParseOption ¶ added in v1.1.1
type ParseOption interface { ReadFileOption // contains filtered or unexported methods }
ParseOption is a type of Option that can be passed to `jwk.Parse()`
func WithPEM ¶ added in v1.1.1
func WithPEM(v bool) ParseOption
WithPEM specifies that the input to `Parse()` is a PEM encoded key.
func WithTypedField ¶ added in v1.2.1
func WithTypedField(name string, object interface{}) ParseOption
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.
type PublicKeyer ¶ added in v1.1.0
type RSAPrivateKey ¶
type RSAPrivateKey interface { Key FromRaw(*rsa.PrivateKey) error D() []byte DP() []byte DQ() []byte E() []byte N() []byte P() []byte Q() []byte QI() []byte }
func NewRSAPrivateKey ¶ added in v1.0.0
func NewRSAPrivateKey() RSAPrivateKey
type RSAPublicKey ¶
func NewRSAPublicKey ¶ added in v1.0.0
func NewRSAPublicKey() RSAPublicKey
type ReadFileOption ¶ added in v1.1.0
type ReadFileOption interface { Option // contains filtered or unexported methods }
ReadFileOption describes options that can be passed to ReadFile.
type Set ¶
type Set interface { // Add adds the specified key. If the key already exists in the set, it is // not added. Add(Key) bool // Clear resets the list of keys associated with this set, emptying the // internal list of `jwk.Key`s Clear() // Get returns the key at index `idx`. If the index is out of range, // then the second return value is false. Get(int) (Key, bool) // Index returns the index where the given key exists, -1 otherwise Index(Key) int // Len returns the number of keys in the set Len() int // LookupKeyID returns the first key matching the given key id. // The second return value is false if there are no keys matching the key id. // The set *may* contain multiple keys with the same key id. If you // need all of them, use `Iterate()` LookupKeyID(string) (Key, bool) // Remove removes the key from the set. Remove(Key) bool // Iterate creates an iterator to iterate through all keys in the set. Iterate(context.Context) KeyIterator // Clone create a new set with identical keys. Keys themselves are not cloned. Clone() (Set, error) }
Set represents JWKS object, a collection of jwk.Key objects.
Sets can be safely converted to and from JSON using the standard `"encoding/json".Marshal` and `"encoding/json".Unmarshal`. However, if you do not know if the payload contains a single JWK or a JWK set, consider using `jwk.Parse()` to always get a `jwk.Set` out of it.
func Fetch ¶
Fetch fetches a JWK resource specified by a URL. The url must be pointing to a resource that is supported by `net/http`.
If you are using the same `jwk.Set` for long periods of time during the lifecycle of your program, and would like to periodically refresh the contents of the object with the data at the remote resource, consider using `jwk.AutoRefresh`, which automatically refreshes jwk.Set objects asynchronously.
func Parse ¶
func Parse(src []byte, options ...ParseOption) (Set, error)
Parse parses JWK from the incoming []byte.
For JWK sets, this is a convenience function. You could just as well call `json.Unmarshal` against an empty set created by `jwk.NewSet()` to parse a JSON buffer into a `jwk.Set`.
This method exists because many times the user does not know before hand if a JWK(s) resource at a remote location contains a single JWK key or a JWK set, and `jwk.Parse()` can handle either case, returning a JWK Set even if the data only contains a single JWK key
If you are looking for more information on how JWKs are parsed, or if you know for sure that you have a single key, please see the documentation for `jwk.ParseKey()`.
func ParseReader ¶ added in v1.1.0
func ParseReader(src io.Reader, options ...ParseOption) (Set, error)
ParseReader parses a JWK set from the incoming byte buffer.
func ParseString ¶
func ParseString(s string, options ...ParseOption) (Set, error)
ParseString parses a JWK set from the incoming string.
func PublicSetOf ¶ added in v1.1.0
PublicSetOf returns a new jwk.Set consisting of public keys of the keys contained in the set.
This is useful when you are generating a set of private keys, and you want to generate the corresponding public versions for the users to verify with.
Be aware that all fields will be copied onto the new public key. It is the caller's responsibility to remove any fields, if necessary.
type SymmetricKey ¶
func NewSymmetricKey ¶ added in v1.0.0
func NewSymmetricKey() SymmetricKey