Overview
The enforce API verifies that an agent’s grant token includes sufficient scope to call a specific tool on a specific connector. It combines JWT verification with manifest-based permission resolution in a single call.enforce()
Check whether a grant token permits a tool call.Parameters
Response: EnforceResult
Example
Capped Scopes
When a token includes a capped scope, pass theamount to enforce against the cap:
amount under a capped
scope is denied with reason_code cap_exceeded and sub_reason
amount_missing (details carries limit). Earlier releases allowed the
missing amount without checking its cap. caps_mode="warn" (on the client or per
call) keeps allowing it and reports the denial in result.would_deny_all
(and in result.would_deny when it is the first warning of the call, so a
call that also lacks a decision grant under decisions_mode="warn" shows the
decision there and amount_missing only in would_deny_all);
caps_mode="off" skips it. The cap covers every tool of the connector, read
tools included, so pass an amount (0 when there is none) for those too. See
Amount caps.
Grant token audience
A grant token requested with anaudience carries it in the aud claim
(RFC 7519 section 4.1.3):
the token is only for that relying party. enforce() checks aud right after
the signature, before revocation and scopes:
aud may be a string or an array of strings; it matches when the expected
audience is one of its values, compared as exact strings (no case folding, no
trailing-slash or prefix matching). The denial’s details carry
token_audience (a list) and, for audience_mismatch, expected_audience.
Audience denials are not relaxed by enforce_mode="permissive": they stay
allowed=False, with the same reason_code, sub_reason and details, in
every enforce mode, because the token was issued for another relying party (or
the client does not know its own audience).
Set the audience on the client, and override it for one call:
To keep the earlier behaviour while you find each service’s audience, create
the client with
audience_check="off"; remove it once audience is set.
load_manifest()
Load a single tool manifest into the client. Must be called beforeenforce() for the corresponding connector.
Example
load_manifests()
Load multiple tool manifests at once.Example
ToolManifest
A manifest declares the permission level required for each tool on a connector.Constructor
get_permission()
Look up the required permission for a tool. ReturnsNone if the tool is not in the manifest.
add_tool()
Add a tool to an existing manifest. Useful for extending pre-built manifests with custom tools.from_file()
Create a manifest from a JSON file on disk:from_dict()
Create a manifest from a Python dictionary:Permission
A class representing the four permission levels in the hierarchy.admin > delete > write > read.
covers()
Check whether this permission level covers a required permission level:is_valid()
Check whether a string is a valid permission level:wrap_tool()
Wrap a LangChainStructuredTool so that enforcement runs automatically before every invocation.
extract_amount (from version 0.7.0) receives the tool call’s keyword
arguments and returns the call’s amount, which is passed to enforce() as
amount. Under a capped scope, a wrapper without it (or an extractor returning
None) denies every call with amount_missing. An extractor that raises
refuses the call with PermissionError before enforce() runs; a value that
is not a finite number is denied with invalid_amount.
Example
FastAPI Integration
UseGrantexAuth from grantex_fastapi as a FastAPI dependency for automatic enforcement on tool execution routes:
Related
- Scope Enforcement guide — end-to-end walkthrough with framework integrations
- TypeScript SDK enforce() — TypeScript API reference
- Tool Manifests concept — permission hierarchy and scope format
- CLI enforce test — dry-run enforcement from the command line