From 6e7d4fac14f7825ca53aed43bb72f2b9a03669b9 Mon Sep 17 00:00:00 2001 From: Elizabeth Thompson Date: Fri, 19 Jun 2026 16:16:09 +0000 Subject: [PATCH] fix(mcp_service): reduce deprecated authlib.jose.errors imports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The authlib.jose module is deprecated since authlib 1.3+ in favour of joserfc. Our MCP service imported four specific error subclasses (BadSignatureError, DecodeError, ExpiredTokenError, JoseError) from the deprecated path. This commit: - jwt_verifier.py: collapse the four imports to a single `JoseError` import. The three specific decode-path except clauses are merged into one `except JoseError` block that discriminates by `e.error` attribute value ("bad_signature", "expired_token", or generic). The header-parse catch is tightened from `except (ValueError, DecodeError)` to `except ValueError` since `_decode_token_header` only raises ValueError. - mcp_config.py: remove the `JoseError` import entirely. The verifier- construction fallback is broadened from `except (ValueError, JoseError)` to `except Exception` — the handler already suppresses details to avoid leaking key material, so no information is lost. Both changes are no-behaviour-change for correct code paths. The filterwarnings call in __init__.py continues to suppress the authlib.jose deprecation warning emitted by fastmcp's internal import. --- superset/mcp_service/jwt_verifier.py | 27 ++++++++++----------------- superset/mcp_service/mcp_config.py | 3 +-- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/superset/mcp_service/jwt_verifier.py b/superset/mcp_service/jwt_verifier.py index 605a2577717b..ef460d6ffebd 100644 --- a/superset/mcp_service/jwt_verifier.py +++ b/superset/mcp_service/jwt_verifier.py @@ -35,12 +35,7 @@ from typing import Any, cast import httpx -from authlib.jose.errors import ( - BadSignatureError, - DecodeError, - ExpiredTokenError, - JoseError, -) +from authlib.jose.errors import JoseError from fastmcp.server.auth.auth import AccessToken from fastmcp.server.auth.providers.jwt import JWTVerifier from mcp.server.auth.middleware.auth_context import AuthContextMiddleware @@ -491,7 +486,7 @@ async def load_access_token(self, token: str) -> AccessToken | None: # noqa: C9 # Step 1: Decode header and check algorithm try: header = self._decode_token_header(token) - except (ValueError, DecodeError) as e: + except ValueError as e: reason = "Malformed token header" _jwt_failure_reason.set(reason) logger.debug("Malformed token header: %s", e) @@ -566,18 +561,16 @@ async def load_access_token(self, token: str) -> AccessToken | None: # noqa: C9 # Step 3: Decode and verify signature try: claims = self.jwt.decode(token, verification_key) - except BadSignatureError: - reason = "Signature verification failed" - _jwt_failure_reason.set(reason) - return None - except ExpiredTokenError: - reason = "Token has expired (detected during decode)" - _jwt_failure_reason.set(reason) - return None except JoseError as e: - reason = "Token decode failed" + error_code = getattr(e, "error", None) + if error_code == "bad_signature": + reason = "Signature verification failed" + elif error_code == "expired_token": + reason = "Token has expired (detected during decode)" + else: + reason = "Token decode failed" + logger.debug("Token decode failed: %s", e) _jwt_failure_reason.set(reason) - logger.debug("Token decode failed: %s", e) return None # Extract client ID for logging diff --git a/superset/mcp_service/mcp_config.py b/superset/mcp_service/mcp_config.py index 33a4e45c142b..150cd48a395b 100644 --- a/superset/mcp_service/mcp_config.py +++ b/superset/mcp_service/mcp_config.py @@ -20,7 +20,6 @@ import secrets from typing import Any, Dict, Optional, Sequence -from authlib.jose.errors import JoseError from fastmcp.server.auth.providers.jwt import JWTVerifier from flask import Flask @@ -379,7 +378,7 @@ def create_default_mcp_auth_factory(app: Flask) -> Optional[Any]: public_key=public_key, secret=secret, ) - except (ValueError, JoseError): + except Exception: # Do not log the exception — it may contain secrets (e.g., key material) logger.error("Failed to create MCP JWT verifier") if not api_key_enabled: