Skip to main content

grantex

Version 0.7.0: enforce() checks the grant audience, requires an amount for capped scopes, and checks current revocation online by default. Per-call revocation settings cannot weaken the client setting. Python 3.9+ remains supported. These are breaking changes: follow the enforcement migration guide. verify_grant_token() alone does not check current revocation. Verify publication in Release Status before installing.

Version 0.6.1: exposes the signed WebAuthn grant evidence reference and webauthn_verified VC attestation field. An evidence reference is not the raw assertion or a current revocation check. Verify issuer, enrollment, RP ID, origin, digest, and current status; see the passkey guide.

Version 0.6.0: adds hosted passkey enrollment sessions and account-level irregularity response policy methods. Both require the server's corresponding feature flags and an authenticated customer handoff for enrollment. Confirm the published version in Release Status before installing.

Server-side portable issuance requires an explicit rollout.

0.5.1: security and reliability fixes. enforce() applies the tightest budget cap and denies malformed, negative or non-finite amounts; the FastAPI enforcer reads the Authorization header; grant-token verification caches the JWKS and runs off the event loop; resource ids are percent-encoded; single-use authorization codes are never retried; and event streams bound connect time at 10 seconds.

0.5.0: agent and principal wallet clients expose reconcile_reservation(). Authorization dictionaries preserve the server's additive evmPayment payload. Automatic x402 HTTP retries are currently provided by the TypeScript adapter, not this SDK. See Base custody setup.

Python SDK for the Grantex delegated authorization protocol — OAuth 2.0 for AI agents.

Grantex lets humans authorize AI agents with verifiable, revocable, audited grants built on JWT and the OAuth 2.0 model. This SDK provides a complete client for the Grantex API.

PyPI Python License

Homepage | Docs | API Reference | Sign Up Free | GitHub

Install

pip install grantex==0.7.0

Quick start

from grantex import AuthorizeParams, ExchangeTokenParams, Grantex, VerifyGrantTokenOptions, verify_grant_token

client = Grantex(api_key="YOUR_API_KEY", audience="https://api.merchant.example")

# 1. Register the agent and its allowed resource, then request authorization
agent = client.agents.register(
    name="Email Assistant",
    description="Reads files and sends email for the principal",
    scopes=["files:read", "email:send"],
    resource_servers=["https://api.merchant.example"],
)
request = client.authorize(AuthorizeParams(
    agent_id=agent.id,
    user_id="usr_01HXYZ...",
    scopes=["files:read", "email:send"],
    audience="https://api.merchant.example",  # must match the relying party
))

# Redirect the user to the consent page — they approve in plain language
print(request.consent_url)

# 2. Exchange the authorization code for a grant token
# (your redirect callback receives the `code` after user approves)
token = client.tokens.exchange(ExchangeTokenParams(code=code, agent_id=agent.id))
# Deliver token.grant_token securely to the agent; do not log it.
print(token.scopes)       # ('files:read', 'email:send')

# 3. Verify locally using keys retrieved from the issuer's JWKS
grant = verify_grant_token(
    token=token.grant_token,
    options=VerifyGrantTokenOptions(
        jwks_uri="https://api.grantex.dev/.well-known/jwks.json",
        audience="https://api.merchant.example",
    ),
)
print(grant.principal_id)  # 'usr_01HXYZ...'

# 4. Revoke when done
client.tokens.revoke(grant.token_id)

Local JWKS verification

Verify grant-token signatures locally using the issuer's public JWKS. The verifier fetches signing keys when needed and caches them; it does not query current grant revocation status. Configure the expected audience for audience-bound tokens:

from grantex import VerifyGrantTokenOptions, verify_grant_token

verified = verify_grant_token(
    token="eyJhbGciOiJSUzI1NiIs...",
    options=VerifyGrantTokenOptions(
        jwks_uri="https://api.grantex.dev/.well-known/jwks.json",
        audience="https://api.merchant.example",
    ),
)

print(verified.scopes)       # ['files:read', 'email:send']
print(verified.principal_id) # 'usr_01HXYZ...'
print(verified.agent_did)    # 'did:web:...'

For a new passkey-approved grant, verified.webauthn_evidence contains the signed assertion digest reference. Pass credential_format="vc-jwt" during exchange to request an opt-in VC containing the full assertion, then inspect client.credentials.verify(vc_jwt).webauthn_verified. Independently trust the issuer and enrollment, check revocation, pin the RP ID and origin, and compare the VC evidence digest with the grant reference. Raw credential public keys can correlate presentations.

PKCE Support

The SDK includes built-in PKCE (Proof Key for Code Exchange) support using the S256 method:

from grantex import AuthorizeParams, ExchangeTokenParams, Grantex, generate_pkce

client = Grantex(api_key="YOUR_API_KEY")

# 1. Generate a PKCE challenge
pkce = generate_pkce()
# pkce.code_verifier        — random 43-char string (keep secret)
# pkce.code_challenge       — SHA-256 hash of verifier (send to server)
# pkce.code_challenge_method — 'S256'

# 2. Pass the challenge when requesting authorization
request = client.authorize(AuthorizeParams(
    agent_id="ag_01HXYZ...",
    user_id="usr_01HXYZ...",
    scopes=["files:read"],
    code_challenge=pkce.code_challenge,
    code_challenge_method=pkce.code_challenge_method,
))

# 3. Exchange the code with the verifier
token = client.tokens.exchange(ExchangeTokenParams(
    code="auth_code_from_redirect",
    agent_id="ag_01HXYZ...",
    code_verifier=pkce.code_verifier,
))

Features

Feature Description
Authorization flow client.authorize() — initiate consent, get grant tokens
Token exchange client.tokens.exchange() — exchange an authorization code for a grant token
Token management client.tokens.verify(), .revoke() — online verification and revocation
Local verification verify_grant_token() — retrieves JWKS, then performs the RS256 signature check locally
Agent management client.agents.register(), .get(), .list(), .update(), .delete()
Grant management client.grants.list(), .get(), .revoke()
Multi-agent delegation client.grants.delegate() — scoped sub-grants with cascade revocation
Audit trail client.audit.log(), .list(), .get() — tamper-evident hash-chained log
Policy engine client.policies.create(), .list(), .update(), .delete()
Anomaly detection client.anomalies.list(), .detect()
Account irregularity response 0.6.0: client.anomalies.get_response_policy(), .set_response_policy("alert_only") (server flag required)
Hosted passkey enrollment 0.6.0: client.webauthn.create_enrollment_session(principal_id=...) after customer authentication (server flag required)
Compliance client.compliance.get_summary(), .export_audit(), .export_grants(), .evidence_pack()
Webhooks client.webhooks.create(), .list(), .delete() + verify_webhook_signature()
Billing client.billing.get_subscription(), .create_checkout(), .create_portal()
SCIM 2.0 client.scim.create_user(), .list_users(), .get_user(), .update_user(), .delete_user()
OIDC SSO client.sso.create_config(), .get_config(), .get_login_url(), .handle_callback()
Agent prepaid wallets Developer policy, principal wallet/policy/approval, and ES256 DPoP agent clients
Commerce V1/OACP client.commerce.get_profile(), .search_catalog(), .create_cart(), .get_ops_health()

Enrollment links are one-use bearer secrets. Alert-only is account-wide and affects the legacy detector's automatic revocation, not other security gates.

Agent prepaid wallets (0.4+)

from grantex import (
    AgentPrepaidWalletClient,
    PrincipalPrepaidWalletClient,
    generate_dpop_key,
)

principal = PrincipalPrepaidWalletClient(
    base_url="https://api.grantex.dev",
    session_token=session_token,
)
principal.create_spend_policy({
    "name": "Research group budget",
    "scopeType": "group",
    "scopeId": "research-agents",
    "effect": "limit",
    "maxAmount": "1000000",
    "windowType": "month",
    "onExceed": "require_approval",
})

agent = AgentPrepaidWalletClient(
    access_token=access_token,
    private_key=generate_dpop_key(),  # persist securely across process restarts
    resource_url="https://grantex.dev/v1/prepaid-wallets",
)
result = agent.authorize_payment({
    "amount": "2500",
    "asset": "USDC",
    "network": "grantex:prepaid",
    "recipient": "merchant:data-api",
    "resource": "https://merchant.example/data",
    "scope": "data:read",
    "merchantId": "merchant:data-api",
    "purpose": "research",
    "maxTimeoutSeconds": 120,
    "idempotencyKey": logical_payment_id,
})

if result.get("status") == "approval_required":
    principal.decide_payment_approval(
        result["approvalRequestId"], "approved", "Exact request reviewed"
    )

The agent client creates a fresh ES256 DPoP proof for each request and binds it to the access token, method, and exact URL. An approved retry must preserve the original wallet, idempotency key, amount, payee, resource, and semantic context. Grantex governs delegated spend; external issuer/custody, KYC, sanctions, settlement, dispute, and reconciliation controls remain operator dependencies.

Commerce V1 / OACP

profile = client.commerce.get_profile(merchant_id="mch_shopify_mgx0n6_22")
products = client.commerce.search_catalog({
    "merchant_id": "mch_shopify_mgx0n6_22",
    "limit": 3,
})

Configuration

from grantex import Grantex

# Explicit API key
client = Grantex(api_key="gx_live_...")

# Or via environment variable
# export GRANTEX_API_KEY=gx_live_...
client = Grantex()

# Custom base URL (self-hosted)
client = Grantex(
    api_key="gx_live_...",
    base_url="https://auth.your-company.com",
)

# Custom timeout (seconds)
client = Grantex(api_key="gx_live_...", timeout=60.0)

The client also works as a context manager:

with Grantex(api_key="gx_live_...") as client:
    agents = client.agents.list()

Error handling

from grantex import Grantex, GrantexApiError, GrantexAuthError, GrantexNetworkError

client = Grantex(api_key="gx_live_...")

try:
    client.agents.get("ag_invalid")
except GrantexAuthError:
    # 401 — invalid or expired API key
    pass
except GrantexApiError as e:
    # Any other API error (4xx/5xx)
    print(e.status_code, e.code, e.message)
except GrantexNetworkError:
    # Connection failure, timeout, DNS error
    pass

Requirements

Grantex Ecosystem

Package Description
@grantex/sdk TypeScript SDK
@grantex/langchain LangChain integration
@grantex/autogen AutoGen integration
@grantex/vercel-ai Vercel AI SDK integration
grantex-crewai CrewAI integration
grantex-openai-agents OpenAI Agents SDK integration
grantex-adk Google ADK integration
@grantex/mcp MCP server for Claude Desktop / Cursor / Windsurf
@grantex/cli Command-line tool

Scope Enforcement (v0.3.1)

Enforce tool-level permissions on any connector — define your own manifests or use the 53 pre-built ones.

from grantex import Grantex, ToolManifest, Permission

grantex = Grantex(api_key="gx_...")

# Define a manifest for any connector — no dependency on Grantex to add support
grantex.load_manifest(ToolManifest(
    connector="my-crm",
    tools={"search": Permission.READ, "create_deal": Permission.WRITE, "delete_account": Permission.DELETE},
))

result = grantex.enforce(grant_token=token, connector="my-crm", tool="delete_account")
# result.allowed = False — "write scope does not permit delete operations"

Features:

  • enforce() — verify JWT + check tool permission via manifest, <1ms
  • wrap_tool() — auto-enforce on LangChain tools
  • GrantexEnforcer — FastAPI dependency for scope enforcement, including decision grants (Grantex-Decision-Grant header, JSON body arguments, case_version callback)
  • Define custom manifests for any connector: inline, from JSON, or auto-generated via CLI
  • 53 pre-built manifests included (Salesforce, HubSpot, Jira, Stripe, SAP, S3, and 47 more)
  • Permission hierarchy: admin > delete > write > read
  • Permissive mode for migration (enforce_mode="permissive")

Full Guide | API Reference

License

Apache 2.0

Ownership

Grantex is owned by Orchestrum Technologies LLP. Inventor and owner: Sanjeev Kumar. Ownership contact: sanjeev@orchestrum.in or mishra.sanjeev@gmail.com.

Metadata

Release files for grantex 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for grantex 0.7.0
File Size Uploaded
grantex-0.7.0.tar.gz 261.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for grantex 0.7.0
File Interpreter ABI Platform
grantex-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 459.6 kB

Release files / grantex-0.7.0.tar.gz

Download URL grantex-0.7.0.tar.gz
Size 261.4 kB
Tags Source
SHA-256 checksum
How to use checksums
be49568b038c5dc5798b6780f3c928bcbe6536ed292b761a0256e5b0c41a1aa5
BLAKE2b-256 checksum
How to use checksums
c11d9a50655e0c8085b2f498c2e47f4eb47648ee68b4850a6e97458341ffcfdc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / grantex-0.7.0-py3-none-any.whl

Download URL grantex-0.7.0-py3-none-any.whl
Size 198.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2f2178cabb073727d58c271b573b0f02da78b337507a42421d9a300dd193d16b
BLAKE2b-256 checksum
How to use checksums
1ef1110a6a9e27911ec1b67fb98466ae02f75e8526d4da729452fa1455511e9a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.7.2

2 release files

0.7.1

2 release files

This release

0.7.0 This release

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.14

2 release files

0.3.13

2 release files

0.3.12

2 release files

0.3.11

2 release files

0.3.10

2 release files

0.3.9

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page