From c3145a9f65d5aa84dd497959585d182dd53ce275 Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Wed, 19 Aug 2026 14:54:34 +0800 Subject: [PATCH] mcp: don't run API keys through JWT validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _resolve_token tried the JWT path before checking for the gns3_ prefix, so every API-key connection logged a spurious "JWT rejected" ERROR from get_token_data. Check the prefix first, and downgrade the JWT-rejected log to WARNING — a rejected token is a client problem, not a server one. --- gns3server/api/routes/mcp/__init__.py | 18 ++++++++++-------- gns3server/services/authentication.py | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/gns3server/api/routes/mcp/__init__.py b/gns3server/api/routes/mcp/__init__.py index 021f66b99..47438b9c8 100644 --- a/gns3server/api/routes/mcp/__init__.py +++ b/gns3server/api/routes/mcp/__init__.py @@ -213,14 +213,16 @@ async def _resolve_token(token: str) -> str | None: Returns None if the token is invalid. """ - # Try JWT first - try: - token_data = auth_service.get_token_data(token) - _jwt_username_var.set(token_data.username) - _jwt_token_version_var.set(token_data.token_version) - return token - except Exception: - pass + # API keys (gns3_...) are never valid JWTs — skip the JWT attempt for them + # so it doesn't log a spurious "JWT rejected" line on every API-key connection. + if not token.startswith("gns3_"): + try: + token_data = auth_service.get_token_data(token) + _jwt_username_var.set(token_data.username) + _jwt_token_version_var.set(token_data.token_version) + return token + except Exception: + pass # Try API key — format: gns3__ → O(1) lookup if token.startswith("gns3_") and _app is not None: diff --git a/gns3server/services/authentication.py b/gns3server/services/authentication.py index 6103ee6f9..90f943b99 100644 --- a/gns3server/services/authentication.py +++ b/gns3server/services/authentication.py @@ -115,10 +115,10 @@ class AuthService: token_use: str = payload.claims.get("type", "access") token_data = TokenData(username=username, token_version=token_version, token_use=token_use) except BadSignatureError as e: - log.error("JWT rejected: bad signature (header alg: '%s', error: %s)", _extract_alg(token), e) + log.warning("JWT rejected: bad signature (header alg: '%s', error: %s)", _extract_alg(token), e) raise auth_error("Invalid token signature") except (JoseError, ValidationError, ValueError) as e: - log.error("JWT rejected: %s: %s (header alg: '%s')", type(e).__name__, e, _extract_alg(token)) + log.warning("JWT rejected: %s: %s (header alg: '%s')", type(e).__name__, e, _extract_alg(token)) raise auth_error(f"Invalid token ({type(e).__name__})") return token_data