PrefectHQ/fastmcp · error · IdentityAssertionError
Assertion is missing resource claim
Error message
Assertion is missing resource claim
What it means
When the token exchange specifies a `resource` (resource indicator, RFC 8707), the assertion must carry a matching signed `resource` claim. FastMCP raises this error when the claim is absent, not a string, or empty — the assertion is not bound to this server, so it cannot be exchanged for a token targeting it.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/identity_assertion.py:432
raise IdentityAssertionError(
f"Assertion missing required scopes: {sorted(missing)}"
)
# 6. The signed client_id and resource claims bind the assertion to the
# presenting client and this server. Checked here — before jti is
# recorded as consumed below — so an assertion presented with the
# wrong binding is rejected without burning replay protection for
# whichever client/server it actually belongs to.
assertion_client_id = claims.get("client_id")
if not assertion_client_id or assertion_client_id != client_id:
raise IdentityAssertionError(
f"Assertion client_id {assertion_client_id!r} does not match "
f"authenticated client {client_id!r}"
)
if resource_url is not None:
assertion_resource = claims.get("resource")
if not isinstance(assertion_resource, str) or not assertion_resource:
raise IdentityAssertionError("Assertion is missing resource claim")
if server_url_has_query(resource_url):
claim_matches = assertion_resource.rstrip("/") == resource_url.rstrip(
"/"
)
else:
claim_matches = normalize_resource_url(
assertion_resource
) == normalize_resource_url(resource_url)
if not claim_matches:
raise IdentityAssertionError(
f"Assertion resource {assertion_resource!r} does not match "
f"this server {resource_url!r}"
)
# 7. jti replay rejection (RFC 7523 §3). Must be a non-empty string —
# an array/object jti is unhashable and would raise TypeError on the
# cache lookup (a 500) instead of a clean invalid_grant.
jti = claims.get("jti")View on GitHub (pinned to 1f02114297)
Solutions
- Configure the IdP/issuer to include the `resource` claim (the MCP server's URL) in assertions.
- Ensure the claim is a plain non-empty string, not an array or null.
- If the deployment doesn't use resource indicators, perform the exchange without a resource parameter so this check is skipped.
- Upgrade the issuer if it predates RFC 8707 resource-indicator support.
Example fix
// before
claims = {"iss": iss, "sub": sub, "aud": aud, "exp": now + 300}
// after
claims = {"iss": iss, "sub": sub, "aud": aud, "resource": server_url, "exp": now + 300} Defensive patterns
Strategy: validation
Validate before calling
def has_resource_claim(claims: dict) -> bool:
r = claims.get("resource")
return isinstance(r, str) and bool(r) Type guard
def is_string_resource(claims: dict) -> bool:
return isinstance(claims.get("resource"), str) and len(claims["resource"]) > 0 Try / catch
try:
token = await exchange(assertion, resource=SERVER_URL)
except IdentityAssertionError as e:
if "missing resource claim" in str(e):
raise ValueError("Issuer does not support RFC 8707 resource indicators") from e
raise Prevention
- Configure the IdP to include the resource indicator in issued assertions.
- Verify the claim is a string, not an audience-style array.
- Only pass resource to the exchange if your issuer actually supports it.
When it happens
Trigger: Calling `validate()` with resource_url set while the assertion payload has no `resource` key, `resource: null`, a non-string (e.g. a list of audiences), or an empty string.
Common situations: IdP not configured to include RFC 8707 resource indicators in assertions; an older issuer predating resource-indicator support; issuer emitting `aud`-style arrays under `resource`; client requesting a token exchange with a resource parameter while its IdP assertion template omits the claim.
Related errors
- Assertion must include exp claim
- Assertion must include sub claim
- Assertion missing required scopes: {sorted(missing)}
- Assertion client_id {assertion_client_id!r} does not match a
- Assertion resource {assertion_resource!r} does not match thi
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/9c9290c79a0f6f29.
Report an issue: GitHub.