PrefectHQ/fastmcp · error · ValueError
CIMD documents cannot use shared-secret auth methods: {v}. U
Error message
CIMD documents cannot use shared-secret auth methods: {v}. Use 'none' or 'private_key_jwt' instead. What it means
A Pydantic ValueError raised by CIMDDocument's token_endpoint_auth_method validator (fastmcp_slim/fastmcp/server/auth/cimd.py:138). CIMD clients authenticate by proving key possession (private_key_jwt) or by 'none'; shared-secret methods (client_secret_post, client_secret_basic, client_secret_jwt) are forbidden because a CIMD document is public metadata — a secret in it would be visible to anyone.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/cimd.py:141
default=None,
description="Client's JSON Web Key Set (for private_key_jwt)",
)
software_id: str | None = Field(
default=None,
description="Unique identifier for the client software",
)
software_version: str | None = Field(
default=None,
description="Version of the client software",
)
@field_validator("token_endpoint_auth_method")
@classmethod
def validate_auth_method(cls, v: str) -> str:
"""Ensure no shared-secret auth methods are used."""
forbidden = {"client_secret_post", "client_secret_basic", "client_secret_jwt"}
if v in forbidden:
raise ValueError(
f"CIMD documents cannot use shared-secret auth methods: {v}. "
"Use 'none' or 'private_key_jwt' instead."
)
return v
@field_validator("redirect_uris")
@classmethod
def validate_redirect_uris(cls, v: list[str]) -> list[str]:
"""Ensure redirect_uris is non-empty and each entry is a valid URI."""
if not v:
raise ValueError("CIMD documents must include at least one redirect_uri")
for uri in v:
if not uri or not uri.strip():
raise ValueError("CIMD redirect_uris must be non-empty strings")
parsed = urlparse(uri)
if not parsed.scheme:
raise ValueError(
f"CIMD redirect_uri must have a scheme (e.g. http:// or https://): {uri!r}"View on GitHub (pinned to 1f02114297)
Solutions
- Set token_endpoint_auth_method to 'private_key_jwt' and publish the corresponding public key in jwks.
- Or set it to 'none' if the client authenticates purely by possessing its metadata URL.
- Remove any client_secret fields from the document — CIMD is public metadata and must never carry secrets.
- If the client genuinely needs a shared secret, use dynamic client registration instead of CIMD.
Example fix
// before
{"token_endpoint_auth_method": "client_secret_post", "client_secret": "hunter2"}
// after
{"token_endpoint_auth_method": "private_key_jwt", "jwks": {"keys": [{"kty": "EC", "crv": "P-256", "x": "...", "y": "..."}]}} Defensive patterns
Strategy: validation
Validate before calling
FORBIDDEN = {'client_secret_post', 'client_secret_basic', 'client_secret_jwt'}
doc = json.loads(raw_cimd_json)
if doc.get('token_endpoint_auth_method') in FORBIDDEN:
raise ValueError("CIMD auth method must be 'none' or 'private_key_jwt'")
if 'client_secret' in doc:
raise ValueError('CIMD documents must not contain client_secret') Type guard
def is_cimd_safe_auth_method(doc: dict) -> bool:
return doc.get('token_endpoint_auth_method') in ('none', 'private_key_jwt') Try / catch
from pydantic import ValidationError
try:
document = CIMDDocument.model_validate(raw_doc)
except ValidationError as e:
logger.error('Invalid CIMD document: %s', e)
raise HTTPException(400, 'invalid_client_metadata') from e Prevention
- Use token_endpoint_auth_method='private_key_jwt' with published jwks, or 'none'.
- Treat CIMD documents as public: never include client_secret or shared secrets.
- If the client needs a shared secret, use dynamic client registration instead of CIMD.
- Lint hosted CIMD JSON in CI to catch secret-bearing fields before they ship.
When it happens
Trigger: Fetching or constructing a CIMDDocument whose token_endpoint_auth_method is 'client_secret_post', 'client_secret_basic', or 'client_secret_jwt'; validation runs on fetch (CIMDFetcher) and when the client is loaded into CIMDClientManager.
Common situations: Reusing an OAuth client registration JSON from a provider that uses client secrets as a CIMD document; a template CIMD file copied from a non-CIMD dynamic-registration client; a client that wants secrets but chose CIMD as its registration mechanism by mistake.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- CIMD documents must include at least one redirect_uri
- CIMD redirect_uris must be non-empty strings
- CIMD redirect_uri must have a scheme (e.g. http:// or https:
- The API key is empty
- The Horizon API key is invalid
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/942a78d750880afc.
Report an issue: GitHub.