@@ -5,13 +5,13 @@ import (
55 "encoding/base64"
66 "fmt"
77 "log"
8+ "maps"
89 "net/http"
910 "net/http/httputil"
1011 "net/url"
1112 "os"
1213 "strconv"
1314 "strings"
14- "sync"
1515 "time"
1616
1717 "github.com/gorilla/handlers"
@@ -43,7 +43,6 @@ type OAuthProxy struct {
4343 provider string
4444 encryptionKey []byte
4545 resourceName string
46- lock sync.Mutex
4746 config * types.Config
4847
4948 ctx context.Context
@@ -53,6 +52,7 @@ type OAuthProxy struct {
5352const (
5453 ModeProxy = "proxy"
5554 ModeForwardAuth = "forward_auth"
55+ Middleware = "middleware"
5656)
5757
5858func NewOAuthProxy (config * types.Config ) (* OAuthProxy , error ) {
@@ -206,7 +206,7 @@ func (p *OAuthProxy) Start(ctx context.Context) error {
206206 return nil
207207}
208208
209- func (p * OAuthProxy ) SetupRoutes (mux * http.ServeMux ) {
209+ func (p * OAuthProxy ) SetupRoutes (mux * http.ServeMux , next http. Handler ) {
210210 provider , err := p .providers .GetProvider (p .provider )
211211 if err != nil {
212212 log .Fatalf ("Failed to get provider: %v" , err )
@@ -216,7 +216,7 @@ func (p *OAuthProxy) SetupRoutes(mux *http.ServeMux) {
216216 tokenHandler := token .NewHandler (p .db )
217217 callbackHandler := callback .NewHandler (p .db , provider , p .encryptionKey , p .GetOAuthClientID (), p .GetOAuthClientSecret (), p .config .RoutePrefix , p .mcpUIManager )
218218 revokeHandler := revoke .NewHandler (p .db )
219- tokenValidator := validate .NewTokenValidator (p .tokenManager , p .mcpUIManager , p .encryptionKey , p .db , provider , p .GetOAuthClientID (), p .GetOAuthClientSecret (), p .metadata .ScopesSupported , p .config .RoutePrefix )
219+ tokenValidator := validate .NewTokenValidator (p .tokenManager , p .mcpUIManager , p .encryptionKey , p .db , provider , p .GetOAuthClientID (), p .GetOAuthClientSecret (), p .metadata .ScopesSupported , p .config .RoutePrefix , p . config . RequiredAuthPaths )
220220 successHandler := success .NewHandler ()
221221
222222 // Get route prefix from config
@@ -239,13 +239,15 @@ func (p *OAuthProxy) SetupRoutes(mux *http.ServeMux) {
239239 mux .HandleFunc ("GET " + prefix + "/auth/mcp-ui/success" , p .withCORS (p .withRateLimit (successHandler )))
240240
241241 // Protect everything else
242- mux .HandleFunc (prefix + "/{path...}" , p .withCORS (p .withRateLimit (tokenValidator .WithTokenValidation (p .mcpProxyHandler ))))
242+ mux .HandleFunc (prefix + "/{path...}" , p .withCORS (p .withRateLimit (tokenValidator .WithTokenValidation (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
243+ p .mcpProxyHandler (w , r , next )
244+ })))))
243245}
244246
245247// GetHandler returns an http.Handler for the OAuth proxy
246248func (p * OAuthProxy ) GetHandler () http.Handler {
247249 mux := http .NewServeMux ()
248- p .SetupRoutes (mux )
250+ p .SetupRoutes (mux , nil )
249251
250252 // Wrap with logging middleware
251253 loggedHandler := handlers .LoggingHandler (os .Stdout , mux )
@@ -335,20 +337,17 @@ func (p *OAuthProxy) protectedResourceMetadataHandler(w http.ResponseWriter, r *
335337 handlerutils .JSON (w , http .StatusOK , metadata )
336338}
337339
338- func (p * OAuthProxy ) mcpProxyHandler (w http.ResponseWriter , r * http.Request ) {
340+ func (p * OAuthProxy ) mcpProxyHandler (w http.ResponseWriter , r * http.Request , next http. Handler ) {
339341 tokenInfo := validate .GetTokenInfo (r )
340342 path := r .PathValue ("path" )
341343
342344 // Check if the access token is expired and refresh if needed
343- if tokenInfo .Props != nil {
345+ if tokenInfo != nil && tokenInfo .Props != nil {
344346 if _ , ok := tokenInfo .Props ["access_token" ].(string ); ok {
345347 // Check if token is expired (with a 5-minute buffer)
346348 expiresAt , ok := tokenInfo .Props ["expires_at" ].(float64 )
347349 if ok && expiresAt > 0 {
348350 if time .Now ().Add (5 * time .Minute ).After (time .Unix (int64 (expiresAt ), 0 )) {
349- // when refreshing token, we need to lock the database to avoid race conditions
350- // otherwise we could get save the old access token into the database when another refresh process is running
351- p .lock .Lock ()
352351 log .Printf ("Access token is expired or will expire soon, attempting to refresh" )
353352
354353 // Get the refresh token
@@ -359,7 +358,6 @@ func (p *OAuthProxy) mcpProxyHandler(w http.ResponseWriter, r *http.Request) {
359358 "error" : "invalid_token" ,
360359 "error_description" : "Access token expired and no refresh token available" ,
361360 })
362- p .lock .Unlock ()
363361 return
364362 }
365363
@@ -371,7 +369,6 @@ func (p *OAuthProxy) mcpProxyHandler(w http.ResponseWriter, r *http.Request) {
371369 "error" : "server_error" ,
372370 "error_description" : "Failed to refresh token" ,
373371 })
374- p .lock .Unlock ()
375372 return
376373 }
377374
@@ -384,7 +381,6 @@ func (p *OAuthProxy) mcpProxyHandler(w http.ResponseWriter, r *http.Request) {
384381 "error" : "server_error" ,
385382 "error_description" : "OAuth credentials not configured" ,
386383 })
387- p .lock .Unlock ()
388384 return
389385 }
390386
@@ -396,7 +392,6 @@ func (p *OAuthProxy) mcpProxyHandler(w http.ResponseWriter, r *http.Request) {
396392 "error" : "invalid_token" ,
397393 "error_description" : "Failed to refresh access token" ,
398394 })
399- p .lock .Unlock ()
400395 return
401396 }
402397
@@ -407,21 +402,20 @@ func (p *OAuthProxy) mcpProxyHandler(w http.ResponseWriter, r *http.Request) {
407402 "error" : "server_error" ,
408403 "error_description" : "Failed to update grant with new token" ,
409404 })
410- p .lock .Unlock ()
411405 return
412406 }
413407
414408 // Update the token info with the new access token for the current request
415409 tokenInfo .Props ["access_token" ] = newTokenInfo .AccessToken
416- p .lock .Unlock ()
417-
418410 log .Printf ("Successfully refreshed access token" )
419411 }
420412 }
421413 }
422414 }
423415
424416 switch p .config .Mode {
417+ case Middleware :
418+ next .ServeHTTP (w , r )
425419 case ModeForwardAuth :
426420 setHeaders (w .Header (), tokenInfo .Props )
427421 case ModeProxy :
@@ -508,13 +502,17 @@ func (p *OAuthProxy) updateGrant(grantID, userID string, oldTokenInfo *tokens.To
508502 return fmt .Errorf ("failed to get grant: %w" , err )
509503 }
510504
511- // Prepare sensitive props data
512- sensitiveProps := map [string ]any {
513- "access_token" : newTokenInfo .AccessToken ,
514- "refresh_token" : newTokenInfo .RefreshToken ,
515- "expires_at" : newTokenInfo .Expiry .Unix (),
505+ sensitiveProps := map [string ]any {}
506+ if oldTokenInfo .Props != nil {
507+ // keep all the old props, that include a lot of the user info
508+ maps .Copy (sensitiveProps , oldTokenInfo .Props )
516509 }
517510
511+ // Prepare sensitive props data
512+ sensitiveProps ["access_token" ] = newTokenInfo .AccessToken
513+ sensitiveProps ["refresh_token" ] = newTokenInfo .RefreshToken
514+ sensitiveProps ["expires_at" ] = newTokenInfo .Expiry .Unix ()
515+
518516 // Add existing user info if available
519517 if grant .Props != nil {
520518 if email , ok := grant .Props ["email" ].(string ); ok {
0 commit comments