Skip to content

Commit c92e2f2

Browse files
authored
fix: jwk refresh in background context and reduced min/max interval (#33)
1 parent e2978e9 commit c92e2f2

File tree

2 files changed

+35
-9
lines changed

2 files changed

+35
-9
lines changed

cmd/serve.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import (
88
"net/http/httputil"
99
"net/url"
1010
"path/filepath"
11-
"time"
1211

1312
"github.com/fsnotify/fsnotify"
1413
"github.com/go-chi/cors"
14+
"github.com/go-logr/stdr"
1515
"github.com/hyprmcp/mcp-gateway/config"
1616
"github.com/hyprmcp/mcp-gateway/log"
1717
"github.com/hyprmcp/mcp-gateway/oauth"
@@ -23,17 +23,21 @@ type ServeOptions struct {
2323
Config string
2424
Addr string
2525
AuthProxyAddr string
26+
Verbosity int
2627
}
2728

2829
func BindServeOptions(cmd *cobra.Command, opts *ServeOptions) {
2930
cmd.Flags().StringVarP(&opts.Config, "config", "c", "config.yaml", "Path to the configuration file")
3031
cmd.Flags().StringVarP(&opts.Addr, "addr", "a", ":9000", "Address to listen on")
3132
cmd.Flags().StringVar(&opts.AuthProxyAddr, "auth-proxy-addr", "", "Address to listen on with the authentication server proxy (advanced feature)")
33+
cmd.Flags().IntVarP(&opts.Verbosity, "verbosity", "v", 0, "Set the logging verbosity; greater number means more logging")
3234
}
3335

3436
func runServe(ctx context.Context, opts ServeOptions) error {
3537
done := make(chan error)
3638

39+
stdr.SetVerbosity(opts.Verbosity)
40+
3741
cfg, err := config.ParseFile(opts.Config)
3842
if err != nil {
3943
return err
@@ -57,7 +61,10 @@ func runServe(ctx context.Context, opts ServeOptions) error {
5761

5862
handler := &delegateHandler{}
5963

60-
if h, err := newRouter(ctx, cfg); err != nil {
64+
routerCtx, routerCancel := context.WithCancel(ctx)
65+
defer func() { routerCancel() }()
66+
67+
if h, err := newRouter(routerCtx, cfg); err != nil {
6168
return err
6269
} else {
6370
handler.delegate = h
@@ -67,10 +74,15 @@ func runServe(ctx context.Context, opts ServeOptions) error {
6774
err := WatchConfigChanges(
6875
opts.Config,
6976
func(c *config.Config) {
77+
newRouterCtx, newRouterCancel := context.WithCancel(ctx)
7078
log.Get(ctx).Info("Reconfiguring server after config change...")
71-
if h, err := newRouter(ctx, c); err != nil {
79+
if h, err := newRouter(newRouterCtx, c); err != nil {
80+
newRouterCancel()
7281
log.Get(ctx).Error(err, "failed to reload server")
7382
} else {
83+
routerCancel()
84+
routerCancel = newRouterCancel
85+
routerCtx = newRouterCtx
7486
handler.delegate = h
7587
}
7688
},
@@ -95,9 +107,7 @@ func runServe(ctx context.Context, opts ServeOptions) error {
95107
func newRouter(ctx context.Context, config *config.Config) (http.Handler, error) {
96108
mux := http.NewServeMux()
97109

98-
newMgrCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
99-
defer cancel()
100-
oauthManager, err := oauth.NewManager(newMgrCtx, config)
110+
oauthManager, err := oauth.NewManager(ctx, config)
101111
if err != nil {
102112
return nil, err
103113
}

oauth/oauth.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import (
1111

1212
"github.com/go-chi/httprate"
1313
"github.com/hyprmcp/mcp-gateway/config"
14+
"github.com/hyprmcp/mcp-gateway/log"
1415
"github.com/lestrrat-go/httprc/v3"
16+
"github.com/lestrrat-go/httprc/v3/errsink"
17+
"github.com/lestrrat-go/httprc/v3/tracesink"
1518
"github.com/lestrrat-go/jwx/v3/jwk"
1619
"github.com/lestrrat-go/jwx/v3/jwt"
1720
)
@@ -23,15 +26,28 @@ type Manager struct {
2326
}
2427

2528
func NewManager(ctx context.Context, config *config.Config) (*Manager, error) {
26-
if cache, err := jwk.NewCache(ctx, httprc.NewClient()); err != nil {
29+
log := log.Get(ctx)
30+
31+
timeoutCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
32+
defer cancel()
33+
34+
if cache, err := jwk.NewCache(ctx, httprc.NewClient(
35+
httprc.WithTraceSink(tracesink.Func(func(ctx context.Context, s string) { log.V(1).Info(s) })),
36+
httprc.WithErrorSink(errsink.NewFunc(func(ctx context.Context, err error) { log.V(1).Error(err, "httprc.NewClient error") })),
37+
)); err != nil {
2738
return nil, fmt.Errorf("jwk cache creation error: %w", err)
2839
} else if meta, err := GetMedatata(config.Authorization.Server); err != nil {
2940
return nil, fmt.Errorf("authorization server metadata error: %w", err)
3041
} else if jwksURI, ok := meta["jwks_uri"].(string); !ok {
3142
return nil, errors.New("no jwks_uri")
32-
} else if err := cache.Register(ctx, jwksURI); err != nil {
43+
} else if err := cache.Register(
44+
timeoutCtx,
45+
jwksURI,
46+
jwk.WithMinInterval(10*time.Second),
47+
jwk.WithMaxInterval(5*time.Minute),
48+
); err != nil {
3349
return nil, fmt.Errorf("jwks registration error: %w", err)
34-
} else if _, err := cache.Refresh(ctx, jwksURI); err != nil {
50+
} else if _, err := cache.Refresh(timeoutCtx, jwksURI); err != nil {
3551
return nil, fmt.Errorf("jwks refresh error: %w", err)
3652
} else if s, err := cache.CachedSet(jwksURI); err != nil {
3753
return nil, fmt.Errorf("jwks cache set error: %w", err)

0 commit comments

Comments
 (0)