Repository: containers/kubernetes-mcp-server

Issue:
[REFACTOR] Remove unnecessary TokenReview validation (ValidateToken flag and related code)
## Background

The kubernetes-mcp-server currently includes a `--validate-token` flag (hidden) that, when enabled, performs a TokenReview request against the Kubernetes API Server to validate the OAuth token. This was implemented as an additional security measure in the HTTP authorization middleware.

## Problem Statement

This token validation step is **unnecessary** because:

1. If a user has an invalid token, they won't be able to access the Kubernetes API Server anyway
2. The actual API calls made by MCP tools will fail with proper authentication errors if the token is invalid
3. The TokenReview adds latency to every authenticated request without providing meaningful additional security
4. It requires the MCP server service account to have `tokenreviews.create` RBAC permissions

## Scope of Changes

The following files need to be modified to remove this functionality:

### Core Implementation
- `pkg/mcp/mcp.go:L274-281` - Remove `KubernetesApiVerifyToken` method
- `pkg/kubernetes/token.go` - Remove `TokenVerifier` interface (entire file)
- `pkg/kubernetes/manager.go:L118-144` - Remove `VerifyToken` method from Manager
- `pkg/kubernetes/provider_single.go:L78+` - Remove `VerifyToken` implementation
- `pkg/kubernetes/provider_kubeconfig.go:L102+` - Remove `VerifyToken` implementation

### HTTP Layer
- `pkg/http/authorization.go:L24-29` - Remove `KubernetesApiTokenVerifier` interface
- `pkg/http/authorization.go:L177-185` - Remove Kubernetes API TokenReview validation block
- `pkg/http/authorization.go:L252-260` - Remove `ValidateWithKubernetesApi` method

### Configuration
- `cmd/kubernetes-mcp-server/cmd/root.go` - Remove `--validate-token` flag and related logic
- `pkg/config/config.go:L44-45` - Remove `ValidateToken` field from StaticConfig

### Tests
- `pkg/kubernetes/provider_single_test.go` - Remove `TestVerifyToken` test
- `pkg/kubernetes/provider_kubeconfig_test.go` - Remove `TestVerifyToken` test
- `pkg/http/http_test.go` - Update tests that use `ValidateToken: true`
- `pkg/http/http_authorization_test.go` - Update/remove tests related to token validation

## Expected Behavior

After this refactoring:
- The `--validate-token` flag will no longer exist
- OAuth token validation will still work (offline JWT validation + OIDC provider validation if configured)
- Invalid tokens will be rejected when actual Kubernetes API calls are made by tools
- Reduced latency for authenticated requests
- Simplified authorization middleware

## Acceptance Criteria

- [ ] `KubernetesApiVerifyToken` method removed from `mcp.Server`
- [ ] `TokenVerifier` interface removed from kubernetes package
- [ ] `VerifyToken` methods removed from Manager and Provider implementations
- [ ] `KubernetesApiTokenVerifier` interface removed from http package
- [ ] `ValidateWithKubernetesApi` method removed from JWTClaims
- [ ] `--validate-token` CLI flag removed
- [ ] `ValidateToken` config field removed
- [ ] All related tests updated or removed
- [ ] All existing tests pass
- [ ] Build succeeds without errors

## Tests

- Verify all existing authorization tests pass after removing ValidateToken functionality
- Ensure OAuth flow still works correctly without TokenReview validation
- Verify that invalid tokens are properly rejected by actual Kubernetes API calls

Hints from issue comments:

Solution patch:
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 456f6ec..14af2f7 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -41,8 +41,6 @@ type StaticConfig struct {
 	RequireOAuth bool `toml:"require_oauth,omitempty"`
 	// OAuthAudience is the valid audience for the OAuth tokens, used for offline JWT claim validation.
 	OAuthAudience string `toml:"oauth_audience,omitempty"`
-	// ValidateToken indicates whether the server should validate the token against the Kubernetes API Server using TokenReview.
-	ValidateToken bool `toml:"validate_token,omitempty"`
 	// AuthorizationURL is the URL of the OIDC authorization server.
 	// It is used for token validation and for STS token exchange.
 	AuthorizationURL string `toml:"authorization_url,omitempty"`
diff --git a/pkg/http/authorization.go b/pkg/http/authorization.go
index 19f6170..b0c8108 100644
--- a/pkg/http/authorization.go
+++ b/pkg/http/authorization.go
@@ -1,11 +1,8 @@
 package http
 
 import (
-	"bytes"
 	"context"
-	"encoding/json"
 	"fmt"
-	"io"
 	"net/http"
 	"strings"
 
@@ -13,7 +10,6 @@ import (
 	"github.com/go-jose/go-jose/v4"
 	"github.com/go-jose/go-jose/v4/jwt"
 	"golang.org/x/oauth2"
-	authenticationapiv1 "k8s.io/api/authentication/v1"
 	"k8s.io/klog/v2"
 	"k8s.io/utils/strings/slices"
 
@@ -21,48 +17,6 @@ import (
 	"github.com/containers/kubernetes-mcp-server/pkg/mcp"
 )
 
-type KubernetesApiTokenVerifier interface {
-	// KubernetesApiVerifyToken TODO: clarify proper implementation
-	KubernetesApiVerifyToken(ctx context.Context, cluster, token, audience string) (*authenticationapiv1.UserInfo, []string, error)
-	// GetTargetParameterName returns the parameter name used for target identification in MCP requests
-	GetTargetParameterName() string
-}
-
-// extractTargetFromRequest extracts cluster parameter from MCP request body
-func extractTargetFromRequest(r *http.Request, targetName string) (string, error) {
-	if r.Body == nil {
-		return "", nil
-	}
-
-	// Read the body
-	body, err := io.ReadAll(r.Body)
-	if err != nil {
-		return "", err
-	}
-
-	// Restore the body for downstream handlers
-	r.Body = io.NopCloser(bytes.NewBuffer(body))
-
-	// Parse the MCP request
-	var mcpRequest struct {
-		Params struct {
-			Arguments map[string]interface{} `json:"arguments"`
-		} `json:"params"`
-	}
-
-	if err := json.Unmarshal(body, &mcpRequest); err != nil {
-		// If we can't parse the request, just return empty cluster (will use default)
-		return "", nil
-	}
-
-	// Extract target parameter
-	if cluster, ok := mcpRequest.Params.Arguments[targetName].(string); ok {
-		return cluster, nil
-	}
-
-	return "", nil
-}
-
 // write401 sends a 401/Unauthorized response with WWW-Authenticate header.
 func write401(w http.ResponseWriter, wwwAuthenticateHeader, errorType, message string) {
 	w.Header().Set("WWW-Authenticate", wwwAuthenticateHeader+fmt.Sprintf(`, error="%s"`, errorType))
@@ -87,7 +41,6 @@ func write401(w http.ResponseWriter, wwwAuthenticateHeader, errorType, message s
 //	    2.1. Raw Token Validation (oidcProvider is nil):
 //	         - The token is validated offline for basic sanity checks (expiration).
 //	         - If OAuthAudience is set, the token is validated against the audience.
-//	         - If ValidateToken is set, the token is then used against the Kubernetes API Server for TokenReview.
 //
 //	         see TestAuthorizationRawToken
 //
@@ -95,7 +48,6 @@ func write401(w http.ResponseWriter, wwwAuthenticateHeader, errorType, message s
 //	         - The token is validated offline for basic sanity checks (audience and expiration).
 //	         - If OAuthAudience is set, the token is validated against the audience.
 //	         - The token is then validated against the OIDC Provider.
-//	         - If ValidateToken is set, the token is then used against the Kubernetes API Server for TokenReview.
 //
 //	         see TestAuthorizationOidcToken
 //
@@ -105,10 +57,9 @@ func write401(w http.ResponseWriter, wwwAuthenticateHeader, errorType, message s
 //	         - The token is then validated against the OIDC Provider.
 //	         - If the token is valid, an external account token exchange is performed using
 //	           the OIDC Provider to obtain a new token with the specified audience and scopes.
-//	         - If ValidateToken is set, the exchanged token is then used against the Kubernetes API Server for TokenReview.
 //
 //	         see TestAuthorizationOidcTokenExchange
-func AuthorizationMiddleware(staticConfig *config.StaticConfig, oidcProvider *oidc.Provider, verifier KubernetesApiTokenVerifier, httpClient *http.Client) func(http.Handler) http.Handler {
+func AuthorizationMiddleware(staticConfig *config.StaticConfig, oidcProvider *oidc.Provider, httpClient *http.Client) func(http.Handler) http.Handler {
 	return func(next http.Handler) http.Handler {
 		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 			if r.URL.Path == healthEndpoint || slices.Contains(WellKnownEndpoints, r.URL.EscapedPath()) {
@@ -170,19 +121,10 @@ func AuthorizationMiddleware(staticConfig *config.StaticConfig, oidcProvider *oi
 				if err == nil {
 					// Replace the original token with the exchanged token
 					token = exchangedToken.AccessToken
-					claims, err = ParseJWTClaims(token)
+					_, err = ParseJWTClaims(token)
 					r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) // TODO: Implement test to verify, THIS IS A CRITICAL PART
 				}
 			}
-			// Kubernetes API Server TokenReview validation
-			if err == nil && staticConfig.ValidateToken {
-				targetParameterName := verifier.GetTargetParameterName()
-				cluster, clusterErr := extractTargetFromRequest(r, targetParameterName)
-				if clusterErr != nil {
-					klog.V(2).Infof("Failed to extract cluster from request, using default: %v", clusterErr)
-				}
-				err = claims.ValidateWithKubernetesApi(r.Context(), staticConfig.OAuthAudience, cluster, verifier)
-			}
 			if err != nil {
 				klog.V(1).Infof("Authentication failed - JWT validation error: %s %s from %s, error: %v", r.Method, r.URL.Path, r.RemoteAddr, err)
 				write401(w, wwwAuthenticateHeader, "invalid_token", "Unauthorized: Invalid token")
@@ -249,16 +191,6 @@ func (c *JWTClaims) ValidateWithProvider(ctx context.Context, audience string, p
 	return nil
 }
 
-func (c *JWTClaims) ValidateWithKubernetesApi(ctx context.Context, audience, cluster string, verifier KubernetesApiTokenVerifier) error {
-	if verifier != nil {
-		_, _, err := verifier.KubernetesApiVerifyToken(ctx, cluster, c.Token, audience)
-		if err != nil {
-			return fmt.Errorf("kubernetes API token validation error: %v", err)
-		}
-	}
-	return nil
-}
-
 func ParseJWTClaims(token string) (*JWTClaims, error) {
 	tkn, err := jwt.ParseSigned(token, allSignatureAlgorithms)
 	if err != nil {
diff --git a/pkg/http/http.go b/pkg/http/http.go
index 84103ac..787ccc1 100644
--- a/pkg/http/http.go
+++ b/pkg/http/http.go
@@ -28,7 +28,7 @@ func Serve(ctx context.Context, mcpServer *mcp.Server, staticConfig *config.Stat
 	mux := http.NewServeMux()
 
 	wrappedMux := RequestMiddleware(
-		AuthorizationMiddleware(staticConfig, oidcProvider, mcpServer, httpClient)(mux),
+		AuthorizationMiddleware(staticConfig, oidcProvider, httpClient)(mux),
 	)
 
 	httpServer := &http.Server{
diff --git a/pkg/kubernetes-mcp-server/cmd/root.go b/pkg/kubernetes-mcp-server/cmd/root.go
index 1834956..87508fd 100644
--- a/pkg/kubernetes-mcp-server/cmd/root.go
+++ b/pkg/kubernetes-mcp-server/cmd/root.go
@@ -70,7 +70,6 @@ const (
 	flagDisableDestructive   = "disable-destructive"
 	flagRequireOAuth         = "require-oauth"
 	flagOAuthAudience        = "oauth-audience"
-	flagValidateToken        = "validate-token"
 	flagAuthorizationURL     = "authorization-url"
 	flagServerUrl            = "server-url"
 	flagCertificateAuthority = "certificate-authority"
@@ -89,7 +88,6 @@ type MCPServerOptions struct {
 	DisableDestructive   bool
 	RequireOAuth         bool
 	OAuthAudience        string
-	ValidateToken        bool
 	AuthorizationURL     string
 	CertificateAuthority string
 	ServerURL            string
@@ -146,8 +144,6 @@ func NewMCPServer(streams genericiooptions.IOStreams) *cobra.Command {
 	_ = cmd.Flags().MarkHidden(flagRequireOAuth)
 	cmd.Flags().StringVar(&o.OAuthAudience, flagOAuthAudience, o.OAuthAudience, "OAuth audience for token claims validation. Optional. If not set, the audience is not validated. Only valid if require-oauth is enabled.")
 	_ = cmd.Flags().MarkHidden(flagOAuthAudience)
-	cmd.Flags().BoolVar(&o.ValidateToken, flagValidateToken, o.ValidateToken, "If true, validates the token against the Kubernetes API Server using TokenReview. Optional. If not set, the token is not validated. Only valid if require-oauth is enabled.")
-	_ = cmd.Flags().MarkHidden(flagValidateToken)
 	cmd.Flags().StringVar(&o.AuthorizationURL, flagAuthorizationURL, o.AuthorizationURL, "OAuth authorization server URL for protected resource endpoint. If not provided, the Kubernetes API server host will be used. Only valid if require-oauth is enabled.")
 	_ = cmd.Flags().MarkHidden(flagAuthorizationURL)
 	cmd.Flags().StringVar(&o.ServerURL, flagServerUrl, o.ServerURL, "Server URL of this application. Optional. If set, this url will be served in protected resource metadata endpoint and tokens will be validated with this audience. If not set, expected audience is kubernetes-mcp-server. Only valid if require-oauth is enabled.")
@@ -211,9 +207,6 @@ func (m *MCPServerOptions) loadFlags(cmd *cobra.Command) {
 	if cmd.Flag(flagOAuthAudience).Changed {
 		m.StaticConfig.OAuthAudience = m.OAuthAudience
 	}
-	if cmd.Flag(flagValidateToken).Changed {
-		m.StaticConfig.ValidateToken = m.ValidateToken
-	}
 	if cmd.Flag(flagAuthorizationURL).Changed {
 		m.StaticConfig.AuthorizationURL = m.AuthorizationURL
 	}
@@ -253,8 +246,8 @@ func (m *MCPServerOptions) Validate() error {
 	if err := toolsets.Validate(m.StaticConfig.Toolsets); err != nil {
 		return err
 	}
-	if !m.StaticConfig.RequireOAuth && (m.StaticConfig.ValidateToken || m.StaticConfig.OAuthAudience != "" || m.StaticConfig.AuthorizationURL != "" || m.StaticConfig.ServerURL != "" || m.StaticConfig.CertificateAuthority != "") {
-		return fmt.Errorf("validate-token, oauth-audience, authorization-url, server-url and certificate-authority are only valid if require-oauth is enabled. Missing --port may implicitly set require-oauth to false")
+	if !m.StaticConfig.RequireOAuth && (m.StaticConfig.OAuthAudience != "" || m.StaticConfig.AuthorizationURL != "" || m.StaticConfig.ServerURL != "" || m.StaticConfig.CertificateAuthority != "") {
+		return fmt.Errorf("oauth-audience, authorization-url, server-url and certificate-authority are only valid if require-oauth is enabled. Missing --port may implicitly set require-oauth to false")
 	}
 	if m.StaticConfig.AuthorizationURL != "" {
 		u, err := url.Parse(m.StaticConfig.AuthorizationURL)
diff --git a/pkg/kubernetes/manager.go b/pkg/kubernetes/manager.go
index 69d1680..df75e64 100644
--- a/pkg/kubernetes/manager.go
+++ b/pkg/kubernetes/manager.go
@@ -9,8 +9,6 @@ import (
 	"strings"
 
 	"github.com/containers/kubernetes-mcp-server/pkg/api"
-	authenticationv1api "k8s.io/api/authentication/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/rest"
 	"k8s.io/client-go/tools/clientcmd"
 	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
@@ -115,34 +113,6 @@ func NewManager(config api.BaseConfig, restConfig *rest.Config, clientCmdConfig
 	return k8s, nil
 }
 
-func (m *Manager) VerifyToken(ctx context.Context, token, audience string) (*authenticationv1api.UserInfo, []string, error) {
-	tokenReviewClient := m.kubernetes.AuthenticationV1().TokenReviews()
-	tokenReview := &authenticationv1api.TokenReview{
-		TypeMeta: metav1.TypeMeta{
-			APIVersion: "authentication.k8s.io/v1",
-			Kind:       "TokenReview",
-		},
-		Spec: authenticationv1api.TokenReviewSpec{
-			Token:     token,
-			Audiences: []string{audience},
-		},
-	}
-
-	result, err := tokenReviewClient.Create(ctx, tokenReview, metav1.CreateOptions{})
-	if err != nil {
-		return nil, nil, fmt.Errorf("failed to create token review: %v", err)
-	}
-
-	if !result.Status.Authenticated {
-		if result.Status.Error != "" {
-			return nil, nil, fmt.Errorf("token authentication failed: %s", result.Status.Error)
-		}
-		return nil, nil, fmt.Errorf("token authentication failed")
-	}
-
-	return &result.Status.User, result.Status.Audiences, nil
-}
-
 func (m *Manager) Derived(ctx context.Context) (*Kubernetes, error) {
 	authorization, ok := ctx.Value(OAuthAuthorizationHeader).(string)
 	if !ok || !strings.HasPrefix(authorization, "Bearer ") {
diff --git a/pkg/kubernetes/provider.go b/pkg/kubernetes/provider.go
index 2ccc588..2abfdeb 100644
--- a/pkg/kubernetes/provider.go
+++ b/pkg/kubernetes/provider.go
@@ -16,7 +16,6 @@ type Provider interface {
 	// For the kubecontext case, a user might be targeting both an OpenShift flavored cluster and a vanilla Kubernetes cluster.
 	// See: https://github.com/containers/kubernetes-mcp-server/pull/372#discussion_r2421592315
 	api.Openshift
-	TokenVerifier
 	GetTargets(ctx context.Context) ([]string, error)
 	GetDerivedKubernetes(ctx context.Context, target string) (*Kubernetes, error)
 	GetDefaultTarget() string
diff --git a/pkg/kubernetes/provider_kubeconfig.go b/pkg/kubernetes/provider_kubeconfig.go
index 2d2feca..2d56f62 100644
--- a/pkg/kubernetes/provider_kubeconfig.go
+++ b/pkg/kubernetes/provider_kubeconfig.go
@@ -8,7 +8,6 @@ import (
 
 	"github.com/containers/kubernetes-mcp-server/pkg/api"
 	"github.com/containers/kubernetes-mcp-server/pkg/kubernetes/watcher"
-	authenticationv1api "k8s.io/api/authentication/v1"
 )
 
 // KubeConfigTargetParameterName is the parameter name used to specify
@@ -99,14 +98,6 @@ func (p *kubeConfigClusterProvider) IsOpenShift(ctx context.Context) bool {
 	return p.managers[p.defaultContext].IsOpenShift(ctx)
 }
 
-func (p *kubeConfigClusterProvider) VerifyToken(ctx context.Context, context, token, audience string) (*authenticationv1api.UserInfo, []string, error) {
-	m, err := p.managerForContext(context)
-	if err != nil {
-		return nil, nil, err
-	}
-	return m.VerifyToken(ctx, token, audience)
-}
-
 func (p *kubeConfigClusterProvider) GetTargets(_ context.Context) ([]string, error) {
 	contextNames := make([]string, 0, len(p.managers))
 	for contextName := range p.managers {
diff --git a/pkg/kubernetes/provider_single.go b/pkg/kubernetes/provider_single.go
index 9802256..3a32864 100644
--- a/pkg/kubernetes/provider_single.go
+++ b/pkg/kubernetes/provider_single.go
@@ -8,7 +8,6 @@ import (
 
 	"github.com/containers/kubernetes-mcp-server/pkg/api"
 	"github.com/containers/kubernetes-mcp-server/pkg/kubernetes/watcher"
-	authenticationv1api "k8s.io/api/authentication/v1"
 )
 
 // singleClusterProvider implements Provider for managing a single
@@ -75,13 +74,6 @@ func (p *singleClusterProvider) IsOpenShift(ctx context.Context) bool {
 	return p.manager.IsOpenShift(ctx)
 }
 
-func (p *singleClusterProvider) VerifyToken(ctx context.Context, target, token, audience string) (*authenticationv1api.UserInfo, []string, error) {
-	if target != "" {
-		return nil, nil, fmt.Errorf("unable to get manager for other context/cluster with %s strategy", p.strategy)
-	}
-	return p.manager.VerifyToken(ctx, token, audience)
-}
-
 func (p *singleClusterProvider) GetTargets(_ context.Context) ([]string, error) {
 	return []string{""}, nil
 }
diff --git a/pkg/kubernetes/token.go b/pkg/kubernetes/token.go
deleted file mode 100644
index f81c3a8..0000000
--- a/pkg/kubernetes/token.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package kubernetes
-
-import (
-	"context"
-
-	authenticationv1api "k8s.io/api/authentication/v1"
-)
-
-type TokenVerifier interface {
-	VerifyToken(ctx context.Context, cluster, token, audience string) (*authenticationv1api.UserInfo, []string, error)
-}
diff --git a/pkg/mcp/mcp.go b/pkg/mcp/mcp.go
index 3c990cc..889601c 100644
--- a/pkg/mcp/mcp.go
+++ b/pkg/mcp/mcp.go
@@ -8,7 +8,6 @@ import (
 	"slices"
 
 	"github.com/modelcontextprotocol/go-sdk/mcp"
-	authenticationapiv1 "k8s.io/api/authentication/v1"
 	"k8s.io/klog/v2"
 	"k8s.io/utils/ptr"
 
@@ -271,15 +270,6 @@ func (s *Server) ServeHTTP() *mcp.StreamableHTTPHandler {
 	})
 }
 
-// KubernetesApiVerifyToken verifies the given token with the audience by
-// sending an TokenReview request to API Server for the specified cluster.
-func (s *Server) KubernetesApiVerifyToken(ctx context.Context, cluster, token, audience string) (*authenticationapiv1.UserInfo, []string, error) {
-	if s.p == nil {
-		return nil, nil, fmt.Errorf("kubernetes cluster provider is not initialized")
-	}
-	return s.p.VerifyToken(ctx, cluster, token, audience)
-}
-
 // GetTargetParameterName returns the parameter name used for target identification in MCP requests
 func (s *Server) GetTargetParameterName() string {
 	if s.p == nil {



Test patch:
diff --git a/internal/test/mock_server.go b/internal/test/mock_server.go
index d7f40bb..f941167 100644
--- a/internal/test/mock_server.go
+++ b/internal/test/mock_server.go
@@ -263,47 +263,3 @@ func (h *InOpenShiftHandler) ServeHTTP(w http.ResponseWriter, req *http.Request)
 	}
 }
 
-const tokenReviewSuccessful = `
-	{
-		"kind": "TokenReview",
-		"apiVersion": "authentication.k8s.io/v1",
-		"spec": {"token": "valid-token"},
-		"status": {
-			"authenticated": true,
-			"user": {
-				"username": "test-user",
-				"groups": ["system:authenticated"]
-			},
-			"audiences": ["the-audience"]
-		}
-	}`
-
-type TokenReviewHandler struct {
-	DiscoveryClientHandler
-	TokenReviewed bool
-}
-
-var _ http.Handler = (*TokenReviewHandler)(nil)
-
-func NewTokenReviewHandler() *TokenReviewHandler {
-	trh := &TokenReviewHandler{}
-	trh.Groups = []string{
-		`{"name":"authentication.k8s.io","versions":[{"groupVersion":"authentication.k8s.io/v1","version":"v1"}],"preferredVersion":{"groupVersion":"authentication.k8s.io/v1","version":"v1"}}`,
-	}
-	return trh
-}
-
-func (h *TokenReviewHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
-	h.DiscoveryClientHandler.ServeHTTP(w, req)
-	if req.URL.EscapedPath() == "/apis/authentication.k8s.io/v1" {
-		w.Header().Set("Content-Type", "application/json")
-		_, _ = w.Write([]byte(`{"kind":"APIResourceList","apiVersion":"v1","groupVersion":"authentication.k8s.io/v1","resources":[{"name":"tokenreviews","singularName":"","namespaced":false,"kind":"TokenReview","verbs":["create"]}]}`))
-		return
-	}
-	if req.URL.EscapedPath() == "/apis/authentication.k8s.io/v1/tokenreviews" {
-		w.Header().Set("Content-Type", "application/json")
-		_, _ = w.Write([]byte(tokenReviewSuccessful))
-		h.TokenReviewed = true
-		return
-	}
-}
diff --git a/pkg/http/http_authorization_test.go b/pkg/http/http_authorization_test.go
index 29b1b73..4a24a1f 100644
--- a/pkg/http/http_authorization_test.go
+++ b/pkg/http/http_authorization_test.go
@@ -41,7 +41,6 @@ func (s *AuthorizationSuite) SetupTest() {
 	// Default Auth settings (overridden in tests as needed)
 	s.OidcProvider = nil
 	s.StaticConfig.RequireOAuth = true
-	s.StaticConfig.ValidateToken = true
 	s.StaticConfig.OAuthAudience = ""
 	s.StaticConfig.StsClientId = ""
 	s.StaticConfig.StsClientSecret = ""
@@ -270,48 +269,6 @@ func (s *AuthorizationSuite) TestAuthorizationUnauthorizedOidcValidation() {
 	})
 }
 
-func (s *AuthorizationSuite) TestAuthorizationUnauthorizedKubernetesValidation() {
-	// Failed Kubernetes TokenReview
-	s.StaticConfig.OAuthAudience = "mcp-server"
-	oidcTestServer := NewOidcTestServer(s.T())
-	s.T().Cleanup(oidcTestServer.Close)
-	rawClaims := `{
-		"iss": "` + oidcTestServer.URL + `",
-		"exp": ` + strconv.FormatInt(time.Now().Add(time.Hour).Unix(), 10) + `,
-		"aud": "mcp-server"
-	}`
-	validOidcToken := oidctest.SignIDToken(oidcTestServer.PrivateKey, "test-oidc-key-id", oidc.RS256, rawClaims)
-	s.OidcProvider = oidcTestServer.Provider
-	s.StartServer()
-	s.StartClient(transport.WithHTTPHeaders(map[string]string{
-		"Authorization": "Bearer " + validOidcToken,
-	}))
-
-	s.Run("Initialize returns error for INVALID KUBERNETES Authorization header", func() {
-		_, err := s.mcpClient.Initialize(s.T().Context(), test.McpInitRequest())
-		s.Require().Error(err, "Expected error creating initial request")
-		s.ErrorContains(err, "transport error: request failed with status 401: Unauthorized: Invalid token")
-	})
-
-	s.Run("Protected resource with INVALID KUBERNETES Authorization header", func() {
-		resp := s.HttpGet("Bearer " + validOidcToken)
-		s.T().Cleanup(func() { _ = resp.Body.Close })
-
-		s.Run("returns 401 - Unauthorized status", func() {
-			s.Equal(401, resp.StatusCode, "Expected HTTP 401 for INVALID KUBERNETES Authorization header")
-		})
-		s.Run("returns WWW-Authenticate header", func() {
-			authHeader := resp.Header.Get("WWW-Authenticate")
-			expected := `Bearer realm="Kubernetes MCP Server", audience="mcp-server", error="invalid_token"`
-			s.Equal(expected, authHeader, "Expected WWW-Authenticate header to match")
-		})
-		s.Run("logs error", func() {
-			s.Contains(s.logBuffer.String(), "Authentication failed - JWT validation error", "Expected log entry for JWT validation error")
-			s.Contains(s.logBuffer.String(), "kubernetes API token validation error: failed to create token review", "Expected log entry for Kubernetes TokenReview error details")
-		})
-	})
-}
-
 func (s *AuthorizationSuite) TestAuthorizationRequireOAuthFalse() {
 	s.StaticConfig.RequireOAuth = false
 	s.StartServer()
@@ -326,43 +283,22 @@ func (s *AuthorizationSuite) TestAuthorizationRequireOAuthFalse() {
 
 func (s *AuthorizationSuite) TestAuthorizationRawToken() {
 	s.MockServer.ResetHandlers()
-	tokenReviewHandler := test.NewTokenReviewHandler()
-	s.MockServer.Handle(tokenReviewHandler)
-
-	cases := []struct {
-		audience      string
-		validateToken bool
-	}{
-		{"", false},           // No audience, no validation
-		{"", true},            // No audience, validation enabled
-		{"mcp-server", false}, // Audience set, no validation
-		{"mcp-server", true},  // Audience set, validation enabled
-	}
-	for _, c := range cases {
-		s.StaticConfig.OAuthAudience = c.audience
-		s.StaticConfig.ValidateToken = c.validateToken
+
+	cases := []string{"", "mcp-server"}
+	for _, audience := range cases {
+		s.StaticConfig.OAuthAudience = audience
 		s.logBuffer.Reset()
 		s.StartServer()
 		s.StartClient(transport.WithHTTPHeaders(map[string]string{
 			"Authorization": "Bearer " + tokenBasicNotExpired,
 		}))
-		tokenReviewHandler.TokenReviewed = false
 
-		s.Run(fmt.Sprintf("Protected resource with audience = '%s' and validate-token = '%t'", c.audience, c.validateToken), func() {
+		s.Run(fmt.Sprintf("Protected resource with audience = '%s'", audience), func() {
 			s.Run("Initialize returns OK for VALID Authorization header", func() {
 				result, err := s.mcpClient.Initialize(s.T().Context(), test.McpInitRequest())
 				s.Require().NoError(err, "Expected no error creating initial request")
 				s.Require().NotNil(result, "Expected initial request to not be nil")
 			})
-
-			s.Run("Performs token validation accordingly", func() {
-				if tokenReviewHandler.TokenReviewed == true && !c.validateToken {
-					s.Fail("Expected token review to be skipped when validate-token is false, but it was performed")
-				}
-				if tokenReviewHandler.TokenReviewed == false && c.validateToken {
-					s.Fail("Expected token review to be performed when validate-token is true, but it was skipped")
-				}
-			})
 		})
 		_ = s.mcpClient.Close()
 		s.mcpClient = nil
@@ -373,8 +309,6 @@ func (s *AuthorizationSuite) TestAuthorizationRawToken() {
 
 func (s *AuthorizationSuite) TestAuthorizationOidcToken() {
 	s.MockServer.ResetHandlers()
-	tokenReviewHandler := test.NewTokenReviewHandler()
-	s.MockServer.Handle(tokenReviewHandler)
 
 	oidcTestServer := NewOidcTestServer(s.T())
 	s.T().Cleanup(oidcTestServer.Close)
@@ -385,44 +319,28 @@ func (s *AuthorizationSuite) TestAuthorizationOidcToken() {
 	}`
 	validOidcToken := oidctest.SignIDToken(oidcTestServer.PrivateKey, "test-oidc-key-id", oidc.RS256, rawClaims)
 
-	cases := []bool{false, true}
-	for _, validateToken := range cases {
-		s.OidcProvider = oidcTestServer.Provider
-		s.StaticConfig.OAuthAudience = "mcp-server"
-		s.StaticConfig.ValidateToken = validateToken
-		s.StartServer()
-		s.StartClient(transport.WithHTTPHeaders(map[string]string{
-			"Authorization": "Bearer " + validOidcToken,
-		}))
-		tokenReviewHandler.TokenReviewed = false
-
-		s.Run(fmt.Sprintf("Protected resource with validate-token = '%t'", validateToken), func() {
-			s.Run("Initialize returns OK for VALID OIDC Authorization header", func() {
-				result, err := s.mcpClient.Initialize(s.T().Context(), test.McpInitRequest())
-				s.Require().NoError(err, "Expected no error creating initial request")
-				s.Require().NotNil(result, "Expected initial request to not be nil")
-			})
+	s.OidcProvider = oidcTestServer.Provider
+	s.StaticConfig.OAuthAudience = "mcp-server"
+	s.StartServer()
+	s.StartClient(transport.WithHTTPHeaders(map[string]string{
+		"Authorization": "Bearer " + validOidcToken,
+	}))
 
-			s.Run("Performs token validation accordingly for VALID OIDC Authorization header", func() {
-				if tokenReviewHandler.TokenReviewed == true && !validateToken {
-					s.Fail("Expected token review to be skipped when validate-token is false, but it was performed")
-				}
-				if tokenReviewHandler.TokenReviewed == false && validateToken {
-					s.Fail("Expected token review to be performed when validate-token is true, but it was skipped")
-				}
-			})
+	s.Run("Protected resource", func() {
+		s.Run("Initialize returns OK for VALID OIDC Authorization header", func() {
+			result, err := s.mcpClient.Initialize(s.T().Context(), test.McpInitRequest())
+			s.Require().NoError(err, "Expected no error creating initial request")
+			s.Require().NotNil(result, "Expected initial request to not be nil")
 		})
-		_ = s.mcpClient.Close()
-		s.mcpClient = nil
-		s.StopServer()
-		s.Require().NoError(s.WaitForShutdown())
-	}
+	})
+	_ = s.mcpClient.Close()
+	s.mcpClient = nil
+	s.StopServer()
+	s.Require().NoError(s.WaitForShutdown())
 }
 
 func (s *AuthorizationSuite) TestAuthorizationOidcTokenExchange() {
 	s.MockServer.ResetHandlers()
-	tokenReviewHandler := test.NewTokenReviewHandler()
-	s.MockServer.Handle(tokenReviewHandler)
 
 	oidcTestServer := NewOidcTestServer(s.T())
 	s.T().Cleanup(oidcTestServer.Close)
@@ -440,43 +358,29 @@ func (s *AuthorizationSuite) TestAuthorizationOidcTokenExchange() {
 		_, _ = fmt.Fprintf(w, `{"access_token":"%s","token_type":"Bearer","expires_in":253402297199}`, validOidcBackendToken)
 	}
 
-	cases := []bool{false, true}
-	for _, validateToken := range cases {
-		s.OidcProvider = oidcTestServer.Provider
-		s.StaticConfig.OAuthAudience = "mcp-server"
-		s.StaticConfig.ValidateToken = validateToken
-		s.StaticConfig.StsClientId = "test-sts-client-id"
-		s.StaticConfig.StsClientSecret = "test-sts-client-secret"
-		s.StaticConfig.StsAudience = "backend-audience"
-		s.StaticConfig.StsScopes = []string{"backend-scope"}
-		s.logBuffer.Reset()
-		s.StartServer()
-		s.StartClient(transport.WithHTTPHeaders(map[string]string{
-			"Authorization": "Bearer " + validOidcClientToken,
-		}))
-		tokenReviewHandler.TokenReviewed = false
-
-		s.Run(fmt.Sprintf("Protected resource with validate-token='%t'", validateToken), func() {
-			s.Run("Initialize returns OK for VALID OIDC EXCHANGE Authorization header", func() {
-				result, err := s.mcpClient.Initialize(s.T().Context(), test.McpInitRequest())
-				s.Require().NoError(err, "Expected no error creating initial request")
-				s.Require().NotNil(result, "Expected initial request to not be nil")
-			})
+	s.OidcProvider = oidcTestServer.Provider
+	s.StaticConfig.OAuthAudience = "mcp-server"
+	s.StaticConfig.StsClientId = "test-sts-client-id"
+	s.StaticConfig.StsClientSecret = "test-sts-client-secret"
+	s.StaticConfig.StsAudience = "backend-audience"
+	s.StaticConfig.StsScopes = []string{"backend-scope"}
+	s.logBuffer.Reset()
+	s.StartServer()
+	s.StartClient(transport.WithHTTPHeaders(map[string]string{
+		"Authorization": "Bearer " + validOidcClientToken,
+	}))
 
-			s.Run("Performs token validation accordingly for VALID OIDC EXCHANGE Authorization header", func() {
-				if tokenReviewHandler.TokenReviewed == true && !validateToken {
-					s.Fail("Expected token review to be skipped when validate-token is false, but it was performed")
-				}
-				if tokenReviewHandler.TokenReviewed == false && validateToken {
-					s.Fail("Expected token review to be performed when validate-token is true, but it was skipped")
-				}
-			})
+	s.Run("Protected resource", func() {
+		s.Run("Initialize returns OK for VALID OIDC EXCHANGE Authorization header", func() {
+			result, err := s.mcpClient.Initialize(s.T().Context(), test.McpInitRequest())
+			s.Require().NoError(err, "Expected no error creating initial request")
+			s.Require().NotNil(result, "Expected initial request to not be nil")
 		})
-		_ = s.mcpClient.Close()
-		s.mcpClient = nil
-		s.StopServer()
-		s.Require().NoError(s.WaitForShutdown())
-	}
+	})
+	_ = s.mcpClient.Close()
+	s.mcpClient = nil
+	s.StopServer()
+	s.Require().NoError(s.WaitForShutdown())
 }
 
 func TestAuthorization(t *testing.T) {
diff --git a/pkg/http/http_test.go b/pkg/http/http_test.go
index 0b7aa10..43b7344 100644
--- a/pkg/http/http_test.go
+++ b/pkg/http/http_test.go
@@ -241,7 +241,7 @@ func TestHealthCheck(t *testing.T) {
 		})
 	})
 	// Health exposed even when require Authorization
-	testCaseWithContext(t, &httpContext{StaticConfig: &config.StaticConfig{RequireOAuth: true, ValidateToken: true, ClusterProviderStrategy: api.ClusterProviderKubeConfig}}, func(ctx *httpContext) {
+	testCaseWithContext(t, &httpContext{StaticConfig: &config.StaticConfig{RequireOAuth: true,  ClusterProviderStrategy: api.ClusterProviderKubeConfig}}, func(ctx *httpContext) {
 		resp, err := http.Get(fmt.Sprintf("http://%s/healthz", ctx.HttpAddress))
 		if err != nil {
 			t.Fatalf("Failed to get health check endpoint with OAuth: %v", err)
@@ -262,7 +262,7 @@ func TestWellKnownReverseProxy(t *testing.T) {
 		".well-known/openid-configuration",
 	}
 	// With No Authorization URL configured
-	testCaseWithContext(t, &httpContext{StaticConfig: &config.StaticConfig{RequireOAuth: true, ValidateToken: true, ClusterProviderStrategy: api.ClusterProviderKubeConfig}}, func(ctx *httpContext) {
+	testCaseWithContext(t, &httpContext{StaticConfig: &config.StaticConfig{RequireOAuth: true,  ClusterProviderStrategy: api.ClusterProviderKubeConfig}}, func(ctx *httpContext) {
 		for _, path := range cases {
 			resp, err := http.Get(fmt.Sprintf("http://%s/%s", ctx.HttpAddress, path))
 			t.Cleanup(func() { _ = resp.Body.Close() })
@@ -285,7 +285,6 @@ func TestWellKnownReverseProxy(t *testing.T) {
 	invalidPayloadConfig := &config.StaticConfig{
 		AuthorizationURL:        invalidPayloadServer.URL,
 		RequireOAuth:            true,
-		ValidateToken:           true,
 		ClusterProviderStrategy: api.ClusterProviderKubeConfig,
 	}
 	testCaseWithContext(t, &httpContext{StaticConfig: invalidPayloadConfig}, func(ctx *httpContext) {
@@ -315,7 +314,6 @@ func TestWellKnownReverseProxy(t *testing.T) {
 	staticConfig := &config.StaticConfig{
 		AuthorizationURL:        testServer.URL,
 		RequireOAuth:            true,
-		ValidateToken:           true,
 		ClusterProviderStrategy: api.ClusterProviderKubeConfig,
 	}
 	testCaseWithContext(t, &httpContext{StaticConfig: staticConfig}, func(ctx *httpContext) {
@@ -365,7 +363,6 @@ func TestWellKnownHeaderPropagation(t *testing.T) {
 	staticConfig := &config.StaticConfig{
 		AuthorizationURL:        testServer.URL,
 		RequireOAuth:            true,
-		ValidateToken:           true,
 		ClusterProviderStrategy: api.ClusterProviderKubeConfig,
 	}
 	testCaseWithContext(t, &httpContext{StaticConfig: staticConfig}, func(ctx *httpContext) {
@@ -479,7 +476,6 @@ func TestWellKnownOverrides(t *testing.T) {
 	baseConfig := config.StaticConfig{
 		AuthorizationURL:        testServer.URL,
 		RequireOAuth:            true,
-		ValidateToken:           true,
 		ClusterProviderStrategy: api.ClusterProviderKubeConfig,
 	}
 	// With Dynamic Client Registration disabled
diff --git a/pkg/kubernetes/provider_kubeconfig_test.go b/pkg/kubernetes/provider_kubeconfig_test.go
index add9475..f140344 100644
--- a/pkg/kubernetes/provider_kubeconfig_test.go
+++ b/pkg/kubernetes/provider_kubeconfig_test.go
@@ -55,38 +55,6 @@ func (s *ProviderKubeconfigTestSuite) TestWithOpenShiftCluster() {
 	})
 }
 
-func (s *ProviderKubeconfigTestSuite) TestVerifyToken() {
-	s.mockServer.Handle(test.NewTokenReviewHandler())
-
-	s.Run("VerifyToken returns UserInfo for non-empty context", func() {
-		userInfo, audiences, err := s.provider.VerifyToken(s.T().Context(), "fake-context", "some-token", "the-audience")
-		s.Require().NoError(err, "Expected no error from VerifyToken with empty target")
-		s.Require().NotNil(userInfo, "Expected UserInfo from VerifyToken with empty target")
-		s.Equalf(userInfo.Username, "test-user", "Expected username test-user, got: %s", userInfo.Username)
-		s.Containsf(userInfo.Groups, "system:authenticated", "Expected group system:authenticated in %v", userInfo.Groups)
-		s.Require().NotNil(audiences, "Expected audiences from VerifyToken with empty target")
-		s.Len(audiences, 1, "Expected audiences from VerifyToken with empty target")
-		s.Containsf(audiences, "the-audience", "Expected audience the-audience in %v", audiences)
-	})
-	s.Run("VerifyToken returns UserInfo for empty context (default context)", func() {
-		userInfo, audiences, err := s.provider.VerifyToken(s.T().Context(), "", "the-token", "the-audience")
-		s.Require().NoError(err, "Expected no error from VerifyToken with empty target")
-		s.Require().NotNil(userInfo, "Expected UserInfo from VerifyToken with empty target")
-		s.Equalf(userInfo.Username, "test-user", "Expected username test-user, got: %s", userInfo.Username)
-		s.Containsf(userInfo.Groups, "system:authenticated", "Expected group system:authenticated in %v", userInfo.Groups)
-		s.Require().NotNil(audiences, "Expected audiences from VerifyToken with empty target")
-		s.Len(audiences, 1, "Expected audiences from VerifyToken with empty target")
-		s.Containsf(audiences, "the-audience", "Expected audience the-audience in %v", audiences)
-	})
-	s.Run("VerifyToken returns error for invalid context", func() {
-		userInfo, audiences, err := s.provider.VerifyToken(s.T().Context(), "invalid-context", "some-token", "the-audience")
-		s.Require().Error(err, "Expected error from VerifyToken with invalid target")
-		s.ErrorContainsf(err, `context "invalid-context" does not exist`, "Expected context does not exist error, got: %v", err)
-		s.Nil(userInfo, "Expected no UserInfo from VerifyToken with invalid target")
-		s.Nil(audiences, "Expected no audiences from VerifyToken with invalid target")
-	})
-}
-
 func (s *ProviderKubeconfigTestSuite) TestGetTargets() {
 	s.Run("GetTargets returns all contexts defined in kubeconfig", func() {
 		targets, err := s.provider.GetTargets(s.T().Context())
diff --git a/pkg/kubernetes/provider_single_test.go b/pkg/kubernetes/provider_single_test.go
index ba2c3ec..9a96c6e 100644
--- a/pkg/kubernetes/provider_single_test.go
+++ b/pkg/kubernetes/provider_single_test.go
@@ -56,28 +56,6 @@ func (s *ProviderSingleTestSuite) TestWithOpenShiftCluster() {
 	})
 }
 
-func (s *ProviderSingleTestSuite) TestVerifyToken() {
-	s.mockServer.Handle(test.NewTokenReviewHandler())
-
-	s.Run("VerifyToken returns UserInfo for empty target (default target)", func() {
-		userInfo, audiences, err := s.provider.VerifyToken(s.T().Context(), "", "the-token", "the-audience")
-		s.Require().NoError(err, "Expected no error from VerifyToken with empty target")
-		s.Require().NotNil(userInfo, "Expected UserInfo from VerifyToken with empty target")
-		s.Equalf(userInfo.Username, "test-user", "Expected username test-user, got: %s", userInfo.Username)
-		s.Containsf(userInfo.Groups, "system:authenticated", "Expected group system:authenticated in %v", userInfo.Groups)
-		s.Require().NotNil(audiences, "Expected audiences from VerifyToken with empty target")
-		s.Len(audiences, 1, "Expected audiences from VerifyToken with empty target")
-		s.Containsf(audiences, "the-audience", "Expected audience the-audience in %v", audiences)
-	})
-	s.Run("VerifyToken returns error for non-empty context", func() {
-		userInfo, audiences, err := s.provider.VerifyToken(s.T().Context(), "non-empty", "the-token", "the-audience")
-		s.Require().Error(err, "Expected error from VerifyToken with non-empty target")
-		s.ErrorContains(err, "unable to get manager for other context/cluster with in-cluster strategy", "Expected error about trying to get other cluster")
-		s.Nil(userInfo, "Expected no UserInfo from VerifyToken with non-empty target")
-		s.Nil(audiences, "Expected no audiences from VerifyToken with non-empty target")
-	})
-}
-
 func (s *ProviderSingleTestSuite) TestGetTargets() {
 	s.Run("GetTargets returns single empty target", func() {
 		targets, err := s.provider.GetTargets(s.T().Context())