{"record":{"id":"591bc19d4a8ae501","repo":"PrefectHQ/fastmcp","slug":"authorization-failed-for-resource-uri-insuffi","errorCode":null,"errorMessage":"Authorization failed for resource '{uri}': insufficient scope (required: {', '.join(missing)})","messagePattern":"Authorization failed for resource '(.+?)': insufficient scope \\(required: (.+?)\\)","errorType":"exception","errorClass":"InsufficientScopeError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/middleware/authorization.py","lineNumber":331,"sourceCode":"        if component is None:\n            component = await fastmcp.fastmcp.get_resource_template(\n                str(uri),\n                version=version,\n            )\n        if component is None:\n            raise AuthorizationError(\n                f\"Authorization failed for resource '{uri}': \"\n                \"not found or not authorized\"\n            )\n\n        # Global auth check\n        token = get_access_token()\n        ctx = AuthContext(token=token, component=component)\n        authorized, missing = await run_auth_checks_with_shortfall(self.auth, ctx)\n        if not authorized:\n            if missing:\n                missing = self._chain_shortfall(missing, ctx, fastmcp.fastmcp)\n                raise InsufficientScopeError(\n                    missing,\n                    message=(\n                        f\"Authorization failed for resource '{uri}': \"\n                        f\"insufficient scope (required: {', '.join(missing)})\"\n                    ),\n                )\n            raise AuthorizationError(\n                f\"Authorization failed for resource '{uri}': insufficient permissions\"\n            )\n\n        return await call_next(context)\n\n    async def on_list_resource_templates(\n        self,\n        context: MiddlewareContext[mt.ListResourceTemplatesRequest],\n        call_next: CallNext[\n            mt.ListResourceTemplatesRequest, Sequence[ResourceTemplate]\n        ],","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/middleware/authorization.py#L313-L349","documentation":"The resource/template was found but the global auth checks returned unauthorized with a non-empty shortfall of missing scopes. The middleware raises InsufficientScopeError naming the required scopes (post _chain_shortfall) so clients can perform scope-upgrade flows (RFC 6750 insufficient_scope).","triggerScenarios":"resources/read for a registered resource whose required scopes (resource-level or global policy) are not all present in the access token — e.g. token has 'data:read' but the resource requires 'data:read' plus 'pii:read'.","commonSituations":"OAuth tokens downscoped or issued before new scopes were added to the resource; scope naming drift after switching auth providers; service accounts missing newly-required scopes; test tokens without production scopes.","solutions":["Re-obtain a token containing every scope listed after 'required:' in the message.","Adjust the OAuth client's requested scopes or provider config so issued tokens include them.","If the resource's scope requirements are wrong, update its auth configuration (requires_scopes / auth policy) in code.","Validate claim mapping (SCOPE claim, audience) between the identity provider and the FastMCP auth server."],"exampleFix":"# before\ntoken = get_token(scopes=['data:read'])\nawait client.read_resource('pii://users/1')  # requires pii:read\n# after\ntoken = get_token(scopes=['data:read', 'pii:read'])\nawait client.read_resource('pii://users/1')","handlingStrategy":"try-catch","validationCode":"claims = decode_jwt(token)\nhave = set(claims.get('scope', '').split())\nassert {'data:read', 'pii:read'}.issubset(have), 'token missing resource scopes'","typeGuard":null,"tryCatchPattern":"from fastmcp.exceptions import InsufficientScopeError\ntry:\n    res = await client.read_resource(uri)\nexcept InsufficientScopeError as e:\n    missing = getattr(e, 'missing_scopes', None) or parse_scopes(str(e))\n    token = await auth_provider.refresh_with_scopes(missing)\n    client.set_auth(BearerAuth(token))\n    res = await client.read_resource(uri)","preventionTips":["Grant tokens all scopes required by protected resources at issuance time.","Implement an insufficient_scope upgrade flow rather than failing hard.","Keep resource requires_scopes config and provider scope catalog in sync.","Re-test tokens after changing auth providers or scope names."],"tags":["auth","oauth","scopes","insufficient-scope"],"backgroundTag":"insufficient-scope","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}