jwk

package
v1.2.30 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2024 License: MIT Imports: 34 Imported by: 648

README

JWK Go Reference

Package jwk implements JWK as described in RFC7517

  • Parse and work with RSA/EC/Symmetric/OKP JWK types
    • Convert to and from JSON
    • Convert to and from raw key types (e.g. *rsa.PrivateKey)
  • Ability to keep a JWKS fresh.

How-to style documentation can be found in the docs directory.

Examples are located in the examples directory (jwk_example_test.go)

Supported key types:

kty Curve Go Key Type
RSA N/A rsa.PrivateKey / rsa.PublicKey (2)
EC P-256
P-384
P-521
secp256k1 (1)
ecdsa.PrivateKey / ecdsa.PublicKey (2)
oct N/A []byte
OKP Ed25519 (1) ed25519.PrivateKey / ed25519.PublicKey (2)
X25519 (1) (jwx/)x25519.PrivateKey / x25519.PublicKey (2)
  • Note 1: Experimental
  • Note 2: Either value or pointers accepted (e.g. rsa.PrivateKey or *rsa.PrivateKey)

SYNOPSIS

Parse a JWK or a JWK set

  // Parse a single JWK key.
  key, err := jwk.ParseKey(...)

  // Parse a JWK set (or a single JWK key)
  set, err := jwk.Parse(...)

Create JWK keys from raw keys

func ExampleNew() {
	// New returns different underlying types of jwk.Key objects
	// depending on the input value.

	// []byte -> jwk.SymmetricKey
	{
		raw := []byte("Lorem Ipsum")
		key, err := jwk.New(raw)
		if err != nil {
			fmt.Printf("failed to create symmetric key: %s\n", err)
			return
		}
		if _, ok := key.(jwk.SymmetricKey); !ok {
			fmt.Printf("expected jwk.SymmetricKey, got %T\n", key)
			return
		}
	}

	// *rsa.PrivateKey -> jwk.RSAPrivateKey
	// *rsa.PublicKey  -> jwk.RSAPublicKey
	{
		raw, err := rsa.GenerateKey(rand.Reader, 2048)
		if err != nil {
			fmt.Printf("failed to generate new RSA privatre key: %s\n", err)
			return
		}

		key, err := jwk.New(raw)
		if err != nil {
			fmt.Printf("failed to create symmetric key: %s\n", err)
			return
		}
		if _, ok := key.(jwk.RSAPrivateKey); !ok {
			fmt.Printf("expected jwk.SymmetricKey, got %T\n", key)
			return
		}
		// PublicKey is omitted for brevity
	}

	// *ecdsa.PrivateKey -> jwk.ECDSAPrivateKey
	// *ecdsa.PublicKey  -> jwk.ECDSAPublicKey
	{
		raw, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
		if err != nil {
			fmt.Printf("failed to generate new ECDSA privatre key: %s\n", err)
			return
		}

		key, err := jwk.New(raw)
		if err != nil {
			fmt.Printf("failed to create symmetric key: %s\n", err)
			return
		}
		if _, ok := key.(jwk.ECDSAPrivateKey); !ok {
			fmt.Printf("expected jwk.SymmetricKey, got %T\n", key)
			return
		}
		// PublicKey is omitted for brevity
	}

	// OUTPUT:
}

Get the JSON representation of a key

func ExampleMarshalJSON() {
	// to get the same values every time, we need to create a static source
	// of "randomness"
	rdr := bytes.NewReader([]byte("01234567890123456789012345678901234567890123456789ABCDEF"))
	raw, err := ecdsa.GenerateKey(elliptic.P384(), rdr)
	if err != nil {
		fmt.Printf("failed to generate new ECDSA privatre key: %s\n", err)
		return
	}

	key, err := jwk.New(raw)
	if err != nil {
		fmt.Printf("failed to create symmetric key: %s\n", err)
		return
	}
	if _, ok := key.(jwk.ECDSAPrivateKey); !ok {
		fmt.Printf("expected jwk.SymmetricKey, got %T\n", key)
		return
	}

	key.Set(jwk.KeyIDKey, "mykey")

	buf, err := json.MarshalIndent(key, "", "  ")
	if err != nil {
		fmt.Printf("failed to marshal key into JSON: %s\n", err)
		return
	}
	fmt.Printf("%s\n", buf)

	// OUTPUT:
	// {
	//   "kty": "EC",
	//   "crv": "P-384",
	//   "d": "ODkwMTIzNDU2Nzg5MDEyMz7deMbyLt8g4cjcxozuIoygLLlAeoQ1AfM9TSvxkFHJ",
	//   "kid": "mykey",
	//   "x": "gvvRMqm1w5aHn7sVNA2QUJeOVcedUnmiug6VhU834gzS9k87crVwu9dz7uLOdoQl",
	//   "y": "7fVF7b6J_6_g6Wu9RuJw8geWxEi5ja9Gp2TSdELm5u2E-M7IF-bsxqcdOj3n1n7N"
	// }
}

Auto-Refresh a key during a long running process

func ExampleAutoRefresh() {
	ctx, cancel := context.WithCancel(context.Background())

	const googleCerts = `https://www.googleapis.com/oauth2/v3/certs`
	ar := jwk.NewAutoRefresh(ctx)

	// Tell *jwk.AutoRefresh that we only want to refresh this JWKS
	// when it needs to (based on Cache-Control or Expires header from
	// the HTTP response). If the calculated minimum refresh interval is less
	// than 15 minutes, don't go refreshing any earlier than 15 minutes.
	ar.Configure(googleCerts, jwk.WithMinRefreshInterval(15*time.Minute))

	// Refresh the JWKS once before getting into the main loop.
	// This allows you to check if the JWKS is available before we start
	// a long-running program
	_, err := ar.Refresh(ctx, googleCerts)
	if err != nil {
		fmt.Printf("failed to refresh google JWKS: %s\n", err)
		return
	}

	// Pretend that this is your program's main loop
MAIN:
	for {
		select {
		case <-ctx.Done():
			break MAIN
		default:
		}
		keyset, err := ar.Fetch(ctx, googleCerts)
		if err != nil {
			fmt.Printf("failed to fetch google JWKS: %s\n", err)
			return
		}
		_ = keyset

		// Do interesting stuff with the keyset... but here, we just
		// sleep for a bit
		time.Sleep(time.Second)

		// Because we're a dummy program, we just cancel the loop now.
		// If this were a real program, you prosumably loop forever
		cancel()
	}
	// OUTPUT:
}

Parse and use a JWK key:


import (
  "encoding/json"
  "log"

  "github.com/lestrrat-go/jwx/jwk"
)

func main() {
  set, err := jwk.Fetch(context.Background(), "https://www.googleapis.com/oauth2/v3/certs")
  if err != nil {
    log.Printf("failed to parse JWK: %s", err)
    return
  }

  // Key sets can be serialized back to JSON
  {
    jsonbuf, err := json.Marshal(set)
    if err != nil {
      log.Printf("failed to marshal key set into JSON: %s", err)
      return
    }
    log.Printf("%s", jsonbuf)
  }

  for it := set.Iterate(context.Background()); it.Next(context.Background()); {
    pair := it.Pair()
    key := pair.Value.(jwk.Key)

    var rawkey interface{} // This is the raw key, like *rsa.PrivateKey or *ecdsa.PrivateKey
    if err := key.Raw(&rawkey); err != nil {
      log.Printf("failed to create public key: %s", err)
      return
    }
    // Use rawkey for jws.Verify() or whatever.
    _ = rawkey

    // You can create jwk.Key from a raw key, too
    fromRawKey, err := jwk.New(rawkey)


    // Keys can be serialized back to JSON
    jsonbuf, err := json.Marshal(key)
    if err != nil {
      log.Printf("failed to marshal key into JSON: %s", err)
      return
    }
    log.Printf("%s", jsonbuf)

    // If you know the underlying Key type (RSA, EC, Symmetric), you can
    // create an empy instance first
    //    key := jwk.NewRSAPrivateKey()
    // ..and then use json.Unmarshal
    //    json.Unmarshal(key, jsonbuf)
    //
    // but if you don't know the type first, you have an abstract type
    // jwk.Key, which can't be used as the first argument to json.Unmarshal
    //
    // In this case, use jwk.Parse()
    fromJsonKey, err := jwk.Parse(jsonbuf)
    if err != nil {
      log.Printf("failed to parse json: %s", err)
      return
    }
    _ = fromJsonKey
    _ = fromRawKey
  }
}

Documentation

Overview

Package jwk implements JWK as described in https://tools.ietf.org/html/rfc7517

Index

Constants

View Source
const (
	ECDSACrvKey = "crv"
	ECDSADKey   = "d"
	ECDSAXKey   = "x"
	ECDSAYKey   = "y"
)
View Source
const (
	KeyTypeKey                = "kty"
	KeyUsageKey               = "use"
	KeyOpsKey                 = "key_ops"
	AlgorithmKey              = "alg"
	KeyIDKey                  = "kid"
	X509URLKey                = "x58"
	X509CertChainKey          = "x5c"
	X509CertThumbprintKey     = "x5t"
	X509CertThumbprintS256Key = "x5t#S256"
)
View Source
const (
	OKPCrvKey = "crv"
	OKPDKey   = "d"
	OKPXKey   = "x"
)
View Source
const (
	RSADKey  = "d"
	RSADPKey = "dp"
	RSADQKey = "dq"
	RSAEKey  = "e"
	RSANKey  = "n"
	RSAPKey  = "p"
	RSAQIKey = "qi"
	RSAQKey  = "q"
)
View Source
const (
	SymmetricOctetsKey = "k"
)

Variables

This section is empty.

Functions

func AssignKeyID added in v1.0.2

func AssignKeyID(key Key, options ...Option) 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 ParseRawKey added in v1.0.6

func ParseRawKey(data []byte, rawkey interface{}) error

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

func Pem(v interface{}) ([]byte, error)

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. The argument to this function 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

func (af *AutoRefresh) Fetch(ctx context.Context, url string) (Set, error)

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) IsRegistered added in v1.2.14

func (af *AutoRefresh) IsRegistered(url string) bool

IsRegistered checks if `url` is registered already.

func (*AutoRefresh) Refresh added in v1.0.7

func (af *AutoRefresh) Refresh(ctx context.Context, url string) (Set, error)

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) Remove added in v1.2.15

func (af *AutoRefresh) Remove(url string) error

Remove removes `url` from the list of urls being watched by jwk.AutoRefresh. If the url is not already registered, returns an error.

func (*AutoRefresh) Snapshot added in v1.0.7

func (af *AutoRefresh) Snapshot() <-chan TargetSnapshot

type AutoRefreshError added in v1.2.5

type AutoRefreshError struct {
	Error error
	URL   string
}

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 DecodeCtx added in v1.2.1

type DecodeCtx interface {
	json.DecodeCtx
	IgnoreParseError() bool
}

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()` FetchOption also implements the `AutoRefreshOption`, and thus can safely be 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 WithFetchWhitelist added in v1.2.14

func WithFetchWhitelist(w Whitelist) FetchOption

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 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

type HTTPClient interface {
	Do(*http.Request) (*http.Response, error)
}

HTTPClient specifies the minimum interface that is required for our JWK fetching tools.

type HeaderIterator added in v1.0.0

type HeaderIterator = mapiter.Iterator

type HeaderPair added in v1.0.0

type HeaderPair = mapiter.Pair

type HeaderVisitor added in v1.0.0

type HeaderVisitor = iter.MapVisitor

type HeaderVisitorFunc added in v1.0.0

type HeaderVisitorFunc = iter.MapVisitorFunc

type InsecureWhitelist added in v1.2.14

type InsecureWhitelist struct{}

InsecureWhitelist allows any URLs to be fetched. This is the default behavior of `jwk.Fetch()`, but this exists to allow other libraries (such as jws, via jws.VerifyAuto) and users to be able to explicitly state that they intend to not check the URLs that are being fetched

func (InsecureWhitelist) IsAllowed added in v1.2.14

func (InsecureWhitelist) IsAllowed(string) bool

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)

	// 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)

	// KeyType returns the `kid` of a JWK
	KeyType() jwa.KeyType
	// KeyUsage returns `use` of a JWK
	KeyUsage() string
	// KeyOps returns `key_ops` of a JWK
	KeyOps() KeyOperationList
	// Algorithm returns `alg` of a JWK
	Algorithm() string
	// KeyID returns `kid` of a JWK
	KeyID() string
	// X509URL returns `x58` of a JWK
	X509URL() string
	// X509CertChain returns `x5c` of a JWK
	X509CertChain() []*x509.Certificate
	// X509CertThumbprint returns `x5t` of a JWK
	X509CertThumbprint() string
	// X509CertThumbprintS256 returns `x5t#S256` of a JWK
	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

func New(key interface{}) (Key, error)

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

func PublicKeyOf(v interface{}) (Key, error)

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 KeyIterator = arrayiter.Iterator

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

type KeyPair added in v1.0.0

type KeyPair = arrayiter.Pair

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 interface {
	SetDecodeCtx(DecodeCtx)
	DecodeCtx() DecodeCtx
}

type MapWhitelist added in v1.2.14

type MapWhitelist struct {
	// contains filtered or unexported fields
}

MapWhitelist is a jwk.Whitelist object comprised of a map of strings. If the URL exists in the map, then the URL is allowed to be fetched.

func NewMapWhitelist added in v1.2.14

func NewMapWhitelist() *MapWhitelist

func (*MapWhitelist) Add added in v1.2.14

func (w *MapWhitelist) Add(pat string) *MapWhitelist

func (*MapWhitelist) IsAllowed added in v1.2.14

func (w *MapWhitelist) IsAllowed(u string) bool

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

type Option = option.Interface

func WithThumbprintHash added in v1.0.2

func WithThumbprintHash(h crypto.Hash) Option

type ParseOption added in v1.1.1

type ParseOption interface {
	ReadFileOption
	AutoRefreshOption
	// contains filtered or unexported methods
}

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()`

func WithIgnoreParseError added in v1.2.19

func WithIgnoreParseError(b bool) ParseOption

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 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 PublicKeyer interface {
	// 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.
	// Returned value must not be the receiver itself.
	PublicKey() (Key, error)
}

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

type RSAPublicKey interface {
	Key
	FromRaw(*rsa.PublicKey) error
	E() []byte
	N() []byte
}

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 RegexpWhitelist added in v1.2.14

type RegexpWhitelist struct {
	// contains filtered or unexported fields
}

RegexpWhitelist is a jwk.Whitelist object comprised of a list of *regexp.Regexp objects. All entries in the list are tried until one matches. If none of the *regexp.Regexp objects match, then the URL is deemed unallowed.

func NewRegexpWhitelist added in v1.2.14

func NewRegexpWhitelist() *RegexpWhitelist

func (*RegexpWhitelist) Add added in v1.2.14

func (*RegexpWhitelist) IsAllowed added in v1.2.14

func (w *RegexpWhitelist) IsAllowed(u string) bool

IsAlloed returns true if any of the patterns in the whitelist returns true.

type Set

type Set interface {
	// Add adds the specified key. If the key already exists in the set, it is
	// not added.
	// This method will be renamed to `AddKey(Key)` in a future major release.
	Add(Key) bool

	// Clear resets the list of keys associated with this set, emptying the
	// internal list of `jwk.Key`s
	// This method will be changed in the future to clear all contents in the
	// `jwk.Set` instead of just the keys.
	Clear()

	// Get returns the key at index `idx`. If the index is out of range,
	// then the second return value is false.
	// This method will be renamed to `Key(int)` in a future major release.
	Get(int) (Key, bool)

	// Field returns the value of a private field in the key set.
	//
	// For the purposes of a key set, any field other than the "keys" field is
	// considered to be a private field. In other words, you cannot use this
	// method to directly access the list of keys in the set
	//
	// This method will be renamed to `Get(string)` in a future major release.
	Field(string) (interface{}, bool)

	// Set sets the value of a single field.
	//
	// 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.
	// 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.

Since v1.2.12, JWK sets with private parameters can be parsed as well. Such private parameters can be accessed via the `Field()` method. If a resource contains a single JWK instead of a JWK set, private parameters are stored in _both_ the resulting `jwk.Set` object and the `jwk.Key` object .

func Fetch

func Fetch(ctx context.Context, urlstring string, options ...FetchOption) (Set, error)

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.

See the list of `jwk.FetchOption`s for various options to tweak the behavior, including providing alternate HTTP Clients, setting a backoff, and using whitelists.

func NewSet added in v1.1.0

func NewSet() Set

NewSet creates and empty `jwk.Set` object

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 function 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

func PublicSetOf(v Set) (Set, error)

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.

func ReadFile added in v1.1.0

func ReadFile(path string, options ...ReadFileOption) (Set, error)

type SymmetricKey

type SymmetricKey interface {
	Key
	FromRaw([]byte) error
	Octets() []byte
}

func NewSymmetricKey added in v1.0.0

func NewSymmetricKey() SymmetricKey

type TargetSnapshot added in v1.0.7

type TargetSnapshot struct {
	URL         string
	NextRefresh time.Time
	LastRefresh time.Time
}

TargetSnapshot is the structure returned by the Snapshot method. It contains information about a url that has been configured in AutoRefresh.

type Whitelist added in v1.2.14

type Whitelist interface {
	IsAllowed(string) bool
}

Whitelist is an interface for a set of URL whitelists. When provided to JWK fetching operations, urls are checked against this object, and the object must return true for urls to be fetched.

type WhitelistFunc added in v1.2.14

type WhitelistFunc func(string) bool

WhitelistFunc is a jwk.Whitelist object based on a function. You can perform any sort of check against the given URL to determine if it can be fetched or not.

func (WhitelistFunc) IsAllowed added in v1.2.14

func (w WhitelistFunc) IsAllowed(u string) bool

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL