11//
2- // Copyright 2024-2025 The Chainloop Authors.
2+ // Copyright 2024-2026 The Chainloop Authors.
33//
44// Licensed under the Apache License, Version 2.0 (the "License");
55// you may not use this file except in compliance with the License.
@@ -24,19 +24,18 @@ import (
2424 "io"
2525 "net/http"
2626 "strings"
27- "time"
2827
2928 v1 "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1"
3029 conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1"
3130 "github.com/chainloop-dev/chainloop/app/controlplane/internal/usercontext/entities"
3231 "github.com/chainloop-dev/chainloop/app/controlplane/pkg/jwt/apitoken"
3332 "github.com/chainloop-dev/chainloop/app/controlplane/pkg/jwt/robotaccount"
3433 "github.com/chainloop-dev/chainloop/app/controlplane/pkg/jwt/user"
34+ "github.com/chainloop-dev/chainloop/pkg/cache"
3535 errorsAPI "github.com/go-kratos/kratos/v2/errors"
3636 "github.com/go-kratos/kratos/v2/log"
3737 "github.com/go-kratos/kratos/v2/middleware"
3838 "github.com/go-kratos/kratos/v2/transport"
39- "github.com/hashicorp/golang-lru/v2/expirable"
4039
4140 "github.com/golang-jwt/jwt/v4"
4241)
@@ -199,6 +198,12 @@ func WithVerifyAudienceFunc(f VerifyAudienceFunc) TokenProviderOption {
199198type options struct {
200199 tokenProviders []providerOption
201200 federatedAuthURL string
201+ claimsCache cache.Cache [* jwt.MapClaims ]
202+ }
203+
204+ // WithClaimsCache sets an external cache for federated JWT claims.
205+ func WithClaimsCache (c cache.Cache [* jwt.MapClaims ]) JWTOption {
206+ return func (o * options ) { o .claimsCache = c }
202207}
203208
204209func withTokenProvider (providerKey string , opts ... TokenProviderOption ) JWTOption {
@@ -251,9 +256,6 @@ func WithJWTMulti(l log.Logger, opts ...JWTOption) middleware.Middleware {
251256 logger .Infof ("federated authentication enabled, using URL: %s" , o .federatedAuthURL )
252257 }
253258
254- // claims cache with 10s TTL and unlimited keys
255- claimsCache := expirable .NewLRU [string , * jwt.MapClaims ](0 , nil , time .Second * 10 )
256-
257259 return func (handler middleware.Handler ) middleware.Handler {
258260 return func (ctx context.Context , req interface {}) (interface {}, error ) {
259261 if header , ok := transport .FromServerContext (ctx ); ok {
@@ -286,7 +288,7 @@ func WithJWTMulti(l log.Logger, opts ...JWTOption) middleware.Middleware {
286288 }
287289
288290 logger .Infof ("calling federated provider, orgName: %s" , orgName )
289- claims , err := callFederatedProvider (o .federatedAuthURL , jwtToken , orgName , claimsCache )
291+ claims , err := callFederatedProvider (ctx , o .federatedAuthURL , jwtToken , orgName , o . claimsCache )
290292 if err != nil {
291293 // if we receive an error from upstream we want to expose it to the user, for example if the federated provider
292294 // is saying that the token is invalid
@@ -333,9 +335,9 @@ func WithJWTMulti(l log.Logger, opts ...JWTOption) middleware.Middleware {
333335
334336// callFederatedProvider calls the federated provider to verify the token
335337// it returns the claims of the token if the token is valid and verified
336- func callFederatedProvider (verifyURL string , jwtToken , orgName string , cache * expirable. LRU [ string , * jwt.MapClaims ]) (* jwt.MapClaims , error ) {
338+ func callFederatedProvider (ctx context. Context , verifyURL string , jwtToken , orgName string , claimsCache cache. Cache [ * jwt.MapClaims ]) (* jwt.MapClaims , error ) {
337339 cacheKey := fmt .Sprintf ("%s:%s" , jwtToken , orgName )
338- if claims , ok := cache .Get (cacheKey ); ok {
340+ if claims , ok , _ := claimsCache .Get (ctx , cacheKey ); ok {
339341 return claims , nil
340342 }
341343
@@ -391,7 +393,7 @@ func callFederatedProvider(verifyURL string, jwtToken, orgName string, cache *ex
391393 "orgName" : response .OrgName ,
392394 }
393395
394- cache . Add ( cacheKey , claims )
396+ _ = claimsCache . Set ( ctx , cacheKey , claims )
395397
396398 return claims , nil
397399}
0 commit comments