package auth import ( "context" "net/http" "strings" "git.d-ma.be/mathias/gitea-mcp/internal/gitea" ) // TokenValidator asks the upstream service who a bearer token belongs to. type TokenValidator interface { ValidateToken(ctx context.Context, token string) (username string, ok bool) } // PassthroughMiddleware lets a caller authenticate with their own Gitea PAT: // if the request's bearer token validates directly against Gitea, it's used // as-is for every upstream call this request makes (gitea-mcp#59), instead of // the server's shared default token. Any other bearer (static token, JWT, or // none) falls through to fallback unchanged — this only adds a capability, it // never removes the existing auth paths. func PassthroughMiddleware(validator TokenValidator, onValid, fallback http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { authz := r.Header.Get("Authorization") token, hasBearer := strings.CutPrefix(authz, "Bearer ") if hasBearer && token != "" { if login, ok := validator.ValidateToken(r.Context(), token); ok { ctx := withCaller(r.Context(), login) ctx = gitea.WithToken(ctx, token) onValid.ServeHTTP(w, r.WithContext(ctx)) return } } fallback.ServeHTTP(w, r) }) }