Skip to main content

grantex

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

Quick start

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

client = Grantex(api_key="YOUR_API_KEY")

# 1. Start the authorization flow
request = client.authorize(AuthorizeParams(
    agent_id="ag_01HXYZ...",
    user_id="usr_01HXYZ...",
    scopes=["files:read", "email:send"],
    audience="https://api.example.com",  # optional; becomes the JWT aud claim
))

# 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="ag_01HXYZ..."))
print(token.grant_token)  # RS256-signed JWT
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",
    ),
)
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 retrieves the current JWKS over the network for each call:

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",
    ),
)

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

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()
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()

Agent prepaid wallets (0.4+)

from grantex import (
    AgentPrepaidWalletClient,
    PrincipalPrepaidWalletClient,
    generate_dpop_key,
)

principal = PrincipalPrepaidWalletClient(
    base_url="https://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

Links

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
  • 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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

grantex-0.4.0.tar.gz (85.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

grantex-0.4.0-py3-none-any.whl (77.9 kB view details)

Uploaded Python 3

File details

Details for the file grantex-0.4.0.tar.gz.

File metadata

  • Download URL: grantex-0.4.0.tar.gz
  • Upload date:
  • Size: 85.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.4

File hashes

Hashes for grantex-0.4.0.tar.gz
Algorithm Hash digest
SHA256 1fa82c867a20e7b49e1779969c29ee0d894342d9f6489ac147e86abc027e3572
MD5 2a6b46b9fda2eee87b1b8fc7d3e8670c
BLAKE2b-256 04ccb765d3d2aca76a01b9f7c9145b0b31cccfa18cb7137d1906ab40ef0149eb

See more details on using hashes here.

File details

Details for the file grantex-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: grantex-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 77.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.4

File hashes

Hashes for grantex-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 62571cdca4787539afbcc4577cef246a9649bddee7a49afdf06c3c385e8569ab
MD5 e12f4e16fcb26f1c89474e513467ca2a
BLAKE2b-256 71487bbc15c1df83f9b775c8b29631655e13d779e23bbb037e585888a2aa9d55

See more details on using hashes here.

Release history Release notifications | RSS feed

0.4.1

2 files

This release

0.4.0 This release

2 files

0.3.14

2 files

0.3.13

2 files

0.3.12

2 files

0.3.11

2 files

0.3.10

2 files

0.3.9

2 files

0.3.8

2 files

0.3.7

2 files

0.3.6

2 files

0.3.5

2 files

0.3.4

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.5

2 files

0.2.4

2 files

0.2.3

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

0.1.9

2 files

0.1.8

2 files

0.1.7

2 files

0.1.6

2 files

0.1.5

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 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