-
Notifications
You must be signed in to change notification settings - Fork 875
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pass Token to authorization.TokenKeyProvider when get keys #2382
Comments
@wenerme Thank you for opening the issue. Could you please help me understand the problem you are suggesting to solve here. Validation of token happens of the hot path, and the expectation is that all necessary keys have already been prefetched by the token key provider (otherwise, the roundtrip of fetching a key would add to the latency of the call). Hence, the provider needs to be able to fetch those keys without knowing what JWT tokens will need to be validated. So, I'm confused why a token key provider should ever need to see a JWT token. If token keys are frefetched and each key has a unique |
@sergeybykov This is my current impl func NewFollowIssuerTokenKeyProvider() *FollowIssuerTokenKeyProvider {
cache, err := lru.New(200)
if err != nil {
panic(err)
}
return &FollowIssuerTokenKeyProvider{cache: cache}
}
type FollowIssuerTokenKeyProvider struct {
cache *lru.Cache
}
func (wa *FollowIssuerTokenKeyProvider) ParseWithClaims(tokenString string, claims jwt.Claims) (*jwt.Token, error) {
return jwt.ParseWithClaims(tokenString, claims, wa.GetKey)
}
func (wa *FollowIssuerTokenKeyProvider) GetKey(token *jwt.Token) (key interface{}, err error) {
kc, _ := token.Claims.(jwt.MapClaims)
if kc == nil {
return nil, errors.New("server invalid claims")
}
iss, _ := kc["iss"].(string)
if iss == "" {
return nil, errors.New("missing issuer")
}
// keycloak
// /protocol/openid-connect/certs
// common
// /.well-known/openid-configuration
// TODO refresh
cv, _ := wa.cache.Get(iss)
set, _ := cv.(jwk.Set)
if set == nil {// for keycloak only
jwkUrl := iss + "/protocol/openid-connect/certs"
set, err = jwk.Fetch(context.Background(), jwkUrl)
if err != nil {
zap.S().With("jwk", jwkUrl, "err", err).Error("load jwk")
return nil, errors.Wrapf(err, "load jwk: %q", jwkUrl)
}
zap.S().With("jwk", jwkUrl).Info("load jwk")
wa.cache.Add(iss, set)
}
kid, _ := token.Header["kid"].(string)
if kid == "" {
keys, _ := set.Get(0)
if keys != nil && set.Len() == 1 && keys.KeyID() == "" {
return key, keys.Raw(&key)
}
return nil, errors.New("jwt header missing kid")
}
if keys, found := set.LookupKeyID(kid); found {
return key, keys.Raw(&key)
}
return nil, fmt.Errorf("jwk key not found: %q", kid)
} GetKey should get the current context, but GetClaims can not get context. when GetClaims, will check the iss domain name first. It's impossible to prefetch pubkey, issuer like |
Thanks for the explanation. This would be a breaking change. Let me ask a couple of people what they think and circle back here. |
@wenerme, the current interface is more user friendly as it is easier to deal with for most use cases. However, your use case is also a valid case. We don't want to break existing users. So proposal would be to create a separate interface like: type RawTokenKeyProvider interface {
GetKey(token *jwt.Token) (interface{}, error)
SupportedMethods() []string
Close()
} And adjust defaultJWTClaimMapper so it can work with either interfaces. Basically keep NewDefaultJWTClaimMapper() that takes TokenKeyProvider, and add another one NewDefaultJWTClaimMapperWithRawKeyProvider() that takes RawTokenKeyProvider. |
Is your feature request related to a problem? Please describe.
JWT has issuer, the cert path is predictable
<issuer>/protocol/openid-connect/certs
<issuer>/.well-known/openid-configuration
) Configurationbenefit
Describe the solution you'd like
make TokenKeyProvider more general
Describe alternatives you've considered
Current TokenKeyProvider restricted to hmac, rsa, ecdsa, but this restriction should consider for default impl only, not for TokenKeyProvider interface.
Additional context
The text was updated successfully, but these errors were encountered: