PrefectHQ/fastmcp · error · ValueError
Failed to extract key ID from token: {e}
Error message
Failed to extract key ID from token: {e} What it means
Raised by _extract_public_key_from_jwks when the token's JOSE header cannot be decoded to obtain the 'kid' (key ID). The method base64-decodes and JSON-parses the first dot-separated segment; malformed segments, non-JSON payloads, or structural problems raise this wrapped ValueError.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/cimd.py:673
Args:
token: JWT token to extract kid from
jwks: JWKS document containing keys
Returns:
PEM-encoded public key
Raises:
ValueError: If key cannot be found or extracted
"""
# Extract kid from token header
try:
header_b64 = token.split(".")[0]
header_b64 += "=" * (4 - len(header_b64) % 4) # Add padding
header = json.loads(base64.urlsafe_b64decode(header_b64))
kid = header.get("kid")
except (IndexError, ValueError, json.JSONDecodeError) as e:
raise ValueError(f"Failed to extract key ID from token: {e}") from e
# Find matching key in JWKS
keys = jwks.get("keys", [])
if not keys:
raise ValueError("JWKS document contains no keys")
matching_key = None
for key in keys:
if kid and key.get("kid") == kid:
matching_key = key
break
if not matching_key:
# If no kid match, try first key as fallback
if len(keys) == 1:
matching_key = keys[0]
self.logger.warning(
"No matching kid in JWKS, using single available key"View on GitHub (pinned to 1f02114297)
Solutions
- Verify the token has three dot-separated base64url segments and a JSON header containing 'kid'
- Confirm you are passing the signed client assertion JWT, not an opaque access token
- Log the first segment (header) and decode it manually to spot corruption/encoding issues
Example fix
// before key = validator._extract_public_key_from_jwks(access_token, jwks) # opaque token // after key = validator._extract_public_key_from_jwks(client_assertion_jwt, jwks) # real JWT with kid
Defensive patterns
Strategy: try-catch
Validate before calling
import base64, json
def token_has_decodable_kid(token: str) -> bool:
try:
h = token.split(".")[0]
h += "=" * (4 - len(h) % 4)
return "kid" in json.loads(base64.urlsafe_b64decode(h))
except Exception:
return False Type guard
def is_well_formed_jwt(token: str) -> bool:
parts = token.split(".")
if len(parts) != 3:
return False
try:
h = parts[0] + "=" * (4 - len(parts[0]) % 4)
json.loads(base64.urlsafe_b64decode(h))
return True
except Exception:
return False Try / catch
try:
key = extract_public_key_from_jwks(token, jwks)
except ValueError as e:
if "Failed to extract key ID" in str(e):
raise AssertionError(f"token is not a decodable JWT: {token[:20]}...") from e
raise Prevention
- Confirm tokens are three-segment base64url JWTs before use
- Pass the signed client assertion, not an opaque access token
- Strip whitespace/newlines when copying tokens from config or logs
- Include a 'kid' header that matches a key in your JWKS
When it happens
Trigger: Passing a token that is not a well-formed three-part JWT (missing dots, garbage prefix); a JWT header that is not valid base64url/JSON; passing a JWE (encrypted token) whose header is not a plain JOSE header; truncation of the token in transit.
Common situations: Debugging with placeholder/opaque tokens instead of real JWTs; clients accidentally sending access tokens (opaque) where a client assertion is required; newline/whitespace corruption of tokens copied from logs or config files.
Related errors
- Malformed assertion header: {e}
- Malformed assertion payload: {e}
- JWKS URI not configured
- Key ID '{kid}' found in JWKS but its key type is unsupported
- Key ID '{kid}' not found in JWKS
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/4e2cbca4aa0bc511.
Report an issue: GitHub.