PrefectHQ/fastmcp · error · AuthorizationError

Authorization failed for resource '{uri}': insufficient perm

Error message

Authorization failed for resource '{uri}': insufficient permissions

What it means

Fallback branch of the global auth check in on_read_resource: auth rejected the request but returned no scope shortfall, so a generic AuthorizationError is raised. Denial came from non-scope logic in the auth provider (roles, custom checks, audience validation) rather than a reportable missing scope.

Source

Thrown at fastmcp_slim/fastmcp/server/middleware/authorization.py:338

                f"Authorization failed for resource '{uri}': "
                "not found or not authorized"
            )

        # Global auth check
        token = get_access_token()
        ctx = AuthContext(token=token, component=component)
        authorized, missing = await run_auth_checks_with_shortfall(self.auth, ctx)
        if not authorized:
            if missing:
                missing = self._chain_shortfall(missing, ctx, fastmcp.fastmcp)
                raise InsufficientScopeError(
                    missing,
                    message=(
                        f"Authorization failed for resource '{uri}': "
                        f"insufficient scope (required: {', '.join(missing)})"
                    ),
                )
            raise AuthorizationError(
                f"Authorization failed for resource '{uri}': insufficient permissions"
            )

        return await call_next(context)

    async def on_list_resource_templates(
        self,
        context: MiddlewareContext[mt.ListResourceTemplatesRequest],
        call_next: CallNext[
            mt.ListResourceTemplatesRequest, Sequence[ResourceTemplate]
        ],
    ) -> Sequence[ResourceTemplate]:
        """Filter resource templates/list response based on auth checks."""
        templates = await call_next(context)

        # STDIO has no auth concept, skip filtering
        from fastmcp.server.context import _current_transport

View on GitHub (pinned to 1f02114297)

Solutions

  1. Update custom auth checks to raise/report a specific reason or shortfall instead of returning bare False, so denials are diagnosable.
  2. Decode the access token and compare roles/claims/aud against the resource's auth policy; fix the token or the policy.
  3. Fix token issuance (roles, audience, issuer) in the identity provider configuration.
  4. Audit middleware ordering and global auth policy so the read isn't blocked by an unintended rule.

Example fix

# before
class OwnerCheck(AuthCheck):
    async def check(self, ctx): return ctx.token.sub == expected_owner  # bare False
# after
class OwnerCheck(AuthCheck):
    async def check(self, ctx):
        if ctx.token.sub != expected_owner:
            raise AuthorizationError('not the resource owner')
        return True
Defensive patterns

Strategy: try-catch

Validate before calling

claims = decode_jwt(token)
assert claims.get('aud') == expected_audience, 'audience mismatch will cause generic denial'
assert required_roles.issubset(set(claims.get('roles', []))), 'token missing roles for resource'

Try / catch

from fastmcp.exceptions import AuthorizationError
try:
    res = await client.read_resource(uri)
except AuthorizationError as e:
    if 'insufficient permissions' in str(e):
        logger.error('Resource denied without scope shortfall; inspect custom auth checks/claims')
    else:
        raise

Prevention

When it happens

Trigger: run_auth_checks_with_shortfall returns (False, []) for the resource's AuthContext — custom AuthChecks returning False without shortfall, role-based checks failing, JWT audience/issuer mismatch, or a deny policy that reports no missing scopes.

Common situations: Custom auth providers whose check() returns False silently; tokens missing required roles/claims rather than scopes; misconfigured audience validation rejecting valid tokens; global default-deny applied to public resources.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/333a0b8c74a443b3. Report an issue: GitHub.