...

Source file src/github.com/MicahParks/keyfunc/v2/multiple.go

Documentation: github.com/MicahParks/keyfunc/v2

     1  package keyfunc
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/golang-jwt/jwt/v5"
     8  )
     9  
    10  // ErrMultipleJWKSSize is returned when the number of JWKS given are not enough to make a MultipleJWKS.
    11  var ErrMultipleJWKSSize = errors.New("multiple JWKS must have one or more remote JWK Set resources")
    12  
    13  // MultipleJWKS manages multiple JWKS and has a field for jwt.Keyfunc.
    14  type MultipleJWKS struct {
    15  	keySelector func(multiJWKS *MultipleJWKS, token *jwt.Token) (key interface{}, err error)
    16  	sets        map[string]*JWKS // No lock is required because this map is read-only after initialization.
    17  }
    18  
    19  // GetMultiple creates a new MultipleJWKS. A map of length one or more JWKS URLs to Options is required.
    20  //
    21  // Be careful when choosing Options for each JWKS in the map. If RefreshUnknownKID is set to true for all JWKS in the
    22  // map then many refresh requests would take place each time a JWT is processed, this should be rate limited by
    23  // RefreshRateLimit.
    24  func GetMultiple(multiple map[string]Options, options MultipleOptions) (multiJWKS *MultipleJWKS, err error) {
    25  	if len(multiple) < 1 {
    26  		return nil, fmt.Errorf("multiple JWKS must have one or more remote JWK Set resources: %w", ErrMultipleJWKSSize)
    27  	}
    28  
    29  	if options.KeySelector == nil {
    30  		options.KeySelector = KeySelectorFirst
    31  	}
    32  
    33  	multiJWKS = &MultipleJWKS{
    34  		sets:        make(map[string]*JWKS, len(multiple)),
    35  		keySelector: options.KeySelector,
    36  	}
    37  
    38  	for u, opts := range multiple {
    39  		jwks, err := Get(u, opts)
    40  		if err != nil {
    41  			return nil, fmt.Errorf("failed to get JWKS from %q: %w", u, err)
    42  		}
    43  		multiJWKS.sets[u] = jwks
    44  	}
    45  
    46  	return multiJWKS, nil
    47  }
    48  
    49  // JWKSets returns a copy of the map of JWK Sets. The map itself is a copy, but the JWKS are not and should be treated
    50  // as read-only.
    51  func (m *MultipleJWKS) JWKSets() map[string]*JWKS {
    52  	sets := make(map[string]*JWKS, len(m.sets))
    53  	for u, jwks := range m.sets {
    54  		sets[u] = jwks
    55  	}
    56  	return sets
    57  }
    58  
    59  // KeySelectorFirst returns the first key found in the multiple JWK Sets.
    60  func KeySelectorFirst(multiJWKS *MultipleJWKS, token *jwt.Token) (key interface{}, err error) {
    61  	kid, alg, err := kidAlg(token)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	for _, jwks := range multiJWKS.sets {
    66  		key, err = jwks.getKey(alg, kid)
    67  		if err == nil {
    68  			return key, nil
    69  		}
    70  	}
    71  	return nil, fmt.Errorf("failed to find key ID in multiple JWKS: %w", ErrKIDNotFound)
    72  }
    73  

View as plain text