PrefectHQ/fastmcp · error · AuthenticationError
Missing client_assertion
Error message
Missing client_assertion
What it means
This AuthenticationError is raised during OAuth client authentication when a client registered with token_endpoint_auth_method='private_key_jwt' sends a token request with a valid client_assertion_type but an absent, empty, or non-string client_assertion form field. The server cannot verify the client's identity without the signed JWT assertion, so the request is rejected before JWT validation is attempted.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/auth.py:282
return await super().authenticate_request(request)
client = await self.provider.get_client(str(client_id))
if not client:
raise AuthenticationError("Invalid client_id")
# Handle private_key_jwt authentication for CIMD clients
if client.token_endpoint_auth_method == "private_key_jwt":
# Validate assertion parameters
assertion_type = form_data.get("client_assertion_type")
assertion = form_data.get("client_assertion")
if assertion_type != JWT_BEARER_ASSERTION_TYPE:
raise AuthenticationError(
f"Invalid client_assertion_type: expected {JWT_BEARER_ASSERTION_TYPE}"
)
if not assertion or not isinstance(assertion, str):
raise AuthenticationError("Missing client_assertion")
# Validate the JWT assertion using CIMD manager
try:
await self._cimd_manager.validate_private_key_jwt(
assertion=assertion,
client=client,
token_endpoint=self._token_endpoint_url,
)
except ValueError as e:
raise AuthenticationError(f"Invalid client assertion: {e}") from e
return client
# Delegate to SDK for other authentication methods
return await super().authenticate_request(request)
class AuthProvider(TokenVerifierProtocol):View on GitHub (pinned to 1f02114297)
Solutions
- Set the client_assertion form field to a properly signed JWT (signed with the client's private key per its CIMD jwks).
- Ensure the assertion is sent as a plain string form value, not as a file or repeated field.
- Verify client_assertion_type is exactly urn:ietf:params:oauth:client-assertion-type:jwt-bearer and both fields travel together in the same form-encoded POST.
- Regenerate or fix the client's token-request code so private_key_jwt clients always attach the assertion.
Example fix
// before curl -X POST /token -d 'client_id=https://client.example.com&grant_type=authorization_code&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' // after curl -X POST /token -d 'client_id=https://client.example.com&grant_type=authorization_code&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=<signed-jwt>'
Defensive patterns
Strategy: validation
Validate before calling
form = token_request_form # dict of form fields
assert form.get('client_assertion_type') == 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
assertion = form.get('client_assertion')
if not isinstance(assertion, str) or not assertion:
raise ValueError('client_assertion form field must be a non-empty string JWT') Type guard
def has_client_assertion(form: dict) -> bool:
a = form.get('client_assertion')
return isinstance(a, str) and len(a) > 0 Prevention
- Always send client_assertion and client_assertion_type together in the token request form body.
- Use a maintained OAuth client library that implements private_key_jwt instead of hand-rolling the form.
- Log form keys (not values) on auth failure to spot missing fields quickly.
- Send the assertion as a plain form field, never as a multipart file part.
When it happens
Trigger: POST to the token endpoint with a client_id whose CIMD document declares private_key_jwt, client_assertion_type set to urn:ietf:params:oauth:client-assertion-type:jwt-bearer, but the form field client_assertion is missing, empty, or not a string (e.g. a file part or repeated form value).
Common situations: Misconfigured OAuth client libraries that send assertion_type but forget the assertion; hand-rolled curl/token scripts missing the client_assertion parameter; form-encoding issues where the assertion arrives as a non-string part; template token-request code that never fills in the assertion.
Related errors
- Invalid JWT assertion
- Invalid client_id
- Invalid client_assertion_type: expected {JWT_BEARER_ASSERTIO
- Invalid client assertion: {e}
- CIMD document must have jwks_uri or jwks for private_key_jwt
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/705708ffaba7c87e.
Report an issue: GitHub.