{"record":{"id":"942a78d750880afc","repo":"PrefectHQ/fastmcp","slug":"cimd-documents-cannot-use-shared-secret-auth-metho","errorCode":null,"errorMessage":"CIMD documents cannot use shared-secret auth methods: {v}. Use 'none' or 'private_key_jwt' instead.","messagePattern":"CIMD documents cannot use shared-secret auth methods: (.+?)\\. Use 'none' or 'private_key_jwt' instead\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/auth/cimd.py","lineNumber":141,"sourceCode":"        default=None,\n        description=\"Client's JSON Web Key Set (for private_key_jwt)\",\n    )\n    software_id: str | None = Field(\n        default=None,\n        description=\"Unique identifier for the client software\",\n    )\n    software_version: str | None = Field(\n        default=None,\n        description=\"Version of the client software\",\n    )\n\n    @field_validator(\"token_endpoint_auth_method\")\n    @classmethod\n    def validate_auth_method(cls, v: str) -> str:\n        \"\"\"Ensure no shared-secret auth methods are used.\"\"\"\n        forbidden = {\"client_secret_post\", \"client_secret_basic\", \"client_secret_jwt\"}\n        if v in forbidden:\n            raise ValueError(\n                f\"CIMD documents cannot use shared-secret auth methods: {v}. \"\n                \"Use 'none' or 'private_key_jwt' instead.\"\n            )\n        return v\n\n    @field_validator(\"redirect_uris\")\n    @classmethod\n    def validate_redirect_uris(cls, v: list[str]) -> list[str]:\n        \"\"\"Ensure redirect_uris is non-empty and each entry is a valid URI.\"\"\"\n        if not v:\n            raise ValueError(\"CIMD documents must include at least one redirect_uri\")\n        for uri in v:\n            if not uri or not uri.strip():\n                raise ValueError(\"CIMD redirect_uris must be non-empty strings\")\n            parsed = urlparse(uri)\n            if not parsed.scheme:\n                raise ValueError(\n                    f\"CIMD redirect_uri must have a scheme (e.g. http:// or https://): {uri!r}\"","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/auth/cimd.py#L123-L159","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n{\"token_endpoint_auth_method\": \"client_secret_post\", \"client_secret\": \"hunter2\"}\n// after\n{\"token_endpoint_auth_method\": \"private_key_jwt\", \"jwks\": {\"keys\": [{\"kty\": \"EC\", \"crv\": \"P-256\", \"x\": \"...\", \"y\": \"...\"}]}}","handlingStrategy":"validation","validationCode":"FORBIDDEN = {'client_secret_post', 'client_secret_basic', 'client_secret_jwt'}\ndoc = json.loads(raw_cimd_json)\nif doc.get('token_endpoint_auth_method') in FORBIDDEN:\n    raise ValueError(\"CIMD auth method must be 'none' or 'private_key_jwt'\")\nif 'client_secret' in doc:\n    raise ValueError('CIMD documents must not contain client_secret')","typeGuard":"def is_cimd_safe_auth_method(doc: dict) -> bool:\n    return doc.get('token_endpoint_auth_method') in ('none', 'private_key_jwt')","tryCatchPattern":"from pydantic import ValidationError\ntry:\n    document = CIMDDocument.model_validate(raw_doc)\nexcept ValidationError as e:\n    logger.error('Invalid CIMD document: %s', e)\n    raise HTTPException(400, 'invalid_client_metadata') from e","preventionTips":["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."],"tags":["pydantic","cimd","validation","oauth-security"],"backgroundTag":"schema-validation-failed","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}