Documentation Index
Fetch the complete documentation index at: https://docs.grantex.dev/llms.txt
Use this file to discover all available pages before exploring further.
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.
from grantex import Grantex
from grantex.manifests.salesforce import manifest as sf
grantex = Grantex(api_key="gx_...")
grantex.load_manifest(sf)
result = grantex.enforce(
grant_token=token,
connector="salesforce",
tool="delete_contact",
)
if not result.allowed:
print(result.reason) # "write scope does not cover delete operations on salesforce"
enforce()
Check whether a grant token permits a tool call.
def enforce(
self,
grant_token: str,
connector: str,
tool: str,
amount: float | None = None,
) -> EnforceResult
Parameters
| Parameter | Type | Required | Description |
|---|
grant_token | str | Yes | The JWT grant token issued by Grantex. Decoded and verified inline. |
connector | str | Yes | The connector name to check against (e.g., "salesforce", "s3"). Must match a loaded manifest. |
tool | str | Yes | The tool name to check (e.g., "delete_contact", "create_lead"). Must be declared in the connector’s manifest. |
amount | float | None | No | Optional 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. |
Response: EnforceResult
| Field | Type | Description |
|---|
allowed | bool | True if the tool call is permitted by the token’s scopes. |
reason | str | Human-readable reason when allowed is False. Empty string when allowed. |
grant_id | str | The grant ID extracted from the JWT grnt (or jti) claim. |
agent_did | str | The agent DID extracted from the JWT agt claim. |
scopes | list[str] | All scopes from the JWT scp claim. |
permission | str | The resolved permission level for this tool from the manifest ("read", "write", "delete", or "admin"). |
connector | str | The connector name that was checked. |
tool | str | The tool name that was checked. |
Example
result = grantex.enforce(
grant_token="eyJhbGciOiJSUzI1NiIs...",
connector="salesforce",
tool="create_lead",
)
if result.allowed:
print(f"Allowed: {result.tool} on {result.connector}")
print(f"Grant: {result.grant_id}, Agent: {result.agent_did}")
else:
print(f"Denied: {result.reason}")
Capped Scopes
When a token includes a capped scope, pass the amount to enforce against the cap:
result = grantex.enforce(
grant_token=token,
connector="stripe",
tool="create_payment_intent",
amount=750,
)
# If token scope is tool:stripe:write:*:capped:500
# result.allowed = False
# result.reason = "amount 750 exceeds cap of 500 on tool:stripe:write:*:capped:500"
load_manifest()
Load a single tool manifest into the client. Must be called before enforce() for the corresponding connector.
def load_manifest(self, manifest: ToolManifest) -> None
Example
from grantex.manifests.salesforce import manifest as sf
grantex.load_manifest(sf)
load_manifests()
Load multiple tool manifests at once.
def load_manifests(self, manifests: list[ToolManifest]) -> None
Example
from grantex.manifests.salesforce import manifest as sf
from grantex.manifests.hubspot import manifest as hs
from grantex.manifests.jira import manifest as jira
grantex.load_manifests([sf, hs, jira])
A manifest declares the permission level required for each tool on a connector.
class ToolManifest:
connector: str
description: str
version: str
def __init__(
self,
connector: str,
tools: dict[str, Permission],
description: str = "",
version: str = "1.0.0",
) -> None: ...
@property
def tool_count(self) -> int: ...
def get_permission(self, tool_name: str) -> Permission | None: ...
def add_tool(self, tool_name: str, permission: Permission) -> None: ...
@classmethod
def from_file(cls, path: str) -> "ToolManifest": ...
@classmethod
def from_dict(cls, data: dict) -> "ToolManifest": ...
Constructor
from grantex import ToolManifest, Permission
manifest = ToolManifest(
connector="inventory-service",
description="Internal warehouse inventory API",
version="1.0.0",
tools={
"get_stock_level": Permission.READ,
"reserve_inventory": Permission.WRITE,
"force_stock_reset": Permission.ADMIN,
},
)
get_permission()
Look up the required permission for a tool. Returns None if the tool is not in the manifest.
perm = manifest.get_permission("reserve_inventory")
# Permission.WRITE
unknown = manifest.get_permission("nonexistent_tool")
# None
Add a tool to an existing manifest. Useful for extending pre-built manifests with custom tools.
from grantex.manifests.salesforce import manifest as sf_manifest
sf_manifest.add_tool("bulk_delete_all", Permission.ADMIN)
sf_manifest.add_tool("export_all_contacts", Permission.READ)
print(sf_manifest.tool_count) # 8 (6 built-in + 2 custom)
from_file()
Create a manifest from a JSON file on disk:
manifest = ToolManifest.from_file("./manifests/inventory-service.json")
grantex.load_manifest(manifest)
The JSON file format:
{
"connector": "inventory-service",
"version": "1.0.0",
"description": "Internal warehouse inventory API",
"tools": {
"get_stock_level": "read",
"reserve_inventory": "write",
"force_stock_reset": "admin"
}
}
from_dict()
Create a manifest from a Python dictionary:
manifest = ToolManifest.from_dict({
"connector": "pricing-engine",
"tools": {
"get_price": "read",
"set_price": "write",
"reset_all_prices": "admin",
},
})
Permission
A class representing the four permission levels in the hierarchy.
class Permission:
READ = "read" # Level 0
WRITE = "write" # Level 1
DELETE = "delete" # Level 2
ADMIN = "admin" # Level 3
Higher levels subsume all lower levels: admin > delete > write > read.
covers()
Check whether this permission level covers a required permission level:
Permission.WRITE.covers(Permission.READ) # True -- write covers read
Permission.WRITE.covers(Permission.DELETE) # False -- write does not cover delete
Permission.ADMIN.covers(Permission.DELETE) # True -- admin covers everything
Permission.READ.covers(Permission.READ) # True -- exact match
is_valid()
Check whether a string is a valid permission level:
Permission.is_valid("write") # True
Permission.is_valid("execute") # False
Wrap a LangChain StructuredTool so that enforcement runs automatically before every invocation.
def wrap_tool(
self,
tool: StructuredTool,
connector: str,
tool_name: str,
grant_token: str | Callable[[], str],
) -> StructuredTool
Example
protected_tool = grantex.wrap_tool(
my_langchain_tool,
connector="salesforce",
tool="create_lead",
grant_token=lambda: current_state["grant_token"],
)
# Use protected_tool in your LangChain agent chain.
# If the token lacks sufficient scope, the tool raises
# PermissionError instead of executing the underlying function.
FastAPI Integration
Use GrantexAuth from grantex_fastapi as a FastAPI dependency for automatic enforcement on tool execution routes:
from grantex_fastapi import GrantexAuth
enforcer = GrantexAuth(grantex)
@app.post("/api/tools/{connector}/{tool}")
async def execute_tool(
connector: str,
tool: str,
auth: EnforceResult = Depends(enforcer),
):
# auth.allowed is guaranteed True here.
# If the token lacked sufficient scope, a 403 was raised automatically.
print(f"Executing {auth.tool} on {auth.connector} for grant {auth.grant_id}")
...