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: EnforceOptions
string
required
The JWT grant token issued by Grantex. Decoded and verified inline.
string
required
The connector name to check against (e.g.,
"salesforce", "s3", "jira"). Must match a loaded manifest.string
required
The tool name to check (e.g.,
"delete_contact", "create_lead"). Must be declared in the connector’s manifest.number
The call’s amount, for capped scopes. When the token includes a capped scope like
tool:stripe:write:*:capped:500, pass the transaction amount to check against the cap. From version 0.8.0 a capped scope denies a call without it (amount_missing).string
The grant token audience this call expects; overrides the client’s
audience. See Grant token audience. From version 0.8.0.Response: EnforceResult
boolean
true if the tool call is permitted by the token’s scopes.string
Human-readable reason when
allowed is false. Empty string when allowed.string
The grant ID extracted from the JWT
grnt (or jti) claim.string
The agent DID extracted from the JWT
agt claim.string[]
All scopes from the JWT
scp claim.string
The resolved permission level for this tool from the manifest (
"read", "write", "delete", or "admin").string
The connector name that was checked.
string
The tool name that was checked.
WouldDeny
In caps or decisions warn mode, the first denial that was let through (
reason_code, sub_reason, reason, details). Absent when there is none.readonly WouldDeny[]
In caps or decisions warn mode, every denial that was let through, in step order (decision, amount cap, call caps, decision consumption);
wouldDeny is its first entry. Absent when there is none.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 reasonCode cap_exceeded and subReason
amount_missing (details carries limit). Earlier releases allowed the
missing amount without checking its cap. capsMode: 'warn' (on the client or per
call) keeps allowing it and reports the denial in result.wouldDenyAll
(and in result.wouldDeny when it is the first warning of the call, so a
call that also lacks a decision grant under decisionsMode: 'warn' shows the
decision there and amount_missing only in wouldDenyAll);
capsMode: '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 (an array) and, for audience_mismatch, expected_audience.
Audience denials are not relaxed by enforceMode: 'permissive': they stay
allowed: false, with the same reasonCode, subReason 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
audienceCheck: 'off'; remove it once audience is set.
loadManifest()
Load a single tool manifest into the client. Must be called beforeenforce() for the corresponding connector.
Example
loadManifests()
Load multiple tool manifests at once.Example
ToolManifest
A manifest declares the permission level required for each tool on a connector.Constructor
getPermission()
Look up the required permission for a tool. Returnsundefined if the tool is not in the manifest.
addTool()
Add a tool to an existing manifest. Useful for extending pre-built manifests with custom tools.fromJSON()
Create a manifest from a plain JSON object (e.g., loaded from a file):Permission
An enum representing the four permission levels in the hierarchy.admin > delete > write > read.
permissionCovers()
Check whether a granted permission level covers a required permission level.Example
wrapTool()
Wrap a LangChainStructuredTool so that enforcement runs automatically before every invocation.
extractAmount (from version 0.8.0) receives the tool’s input 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 undefined or null)
denies every call with amount_missing. An extractor that throws refuses the
call before enforce() runs; a value that is not a finite number is denied
with invalid_amount.
Example
enforceMiddleware()
Express middleware that enforces scope on every request to a route.extractAmount (from version 0.8.0) returns the request’s amount for a
capped scope. Without it, a capped scope answers 403 with reason
cap_exceeded and subReason amount_missing. An extractor that throws, or
returns something that is not a finite number, answers 403 with
invalid_amount.
Example
Related
- Scope Enforcement guide — end-to-end walkthrough with framework integrations
- Python SDK enforce() — Python API reference
- Tool Manifests concept — permission hierarchy and scope format
- CLI enforce test — dry-run enforcement from the command line