Grantex Protocol Specification

March 20, 2026 · View on GitHub

Version: 1.0 Status: Final Last updated: February 2026 (rev 3)

Specification is now frozen. Changes require a new version.


Abstract

Grantex defines an open protocol for delegated authorization of AI agents acting on behalf of human users. It specifies: cryptographic agent identity, a human-consent-based grant flow, a signed token format, a revocation model, an append-only audit trail schema, a policy engine for automated authorization decisions, enterprise identity federation, and anomaly detection for runtime behavioral monitoring.


1. Motivation

AI agents increasingly take autonomous actions — submitting forms, initiating payments, sending communications — on behalf of humans across third-party services. No interoperable standard exists for:

  1. Verifying that an agent is who it claims to be
  2. Confirming that a specific human authorized a specific agent to perform a specific action
  3. Revoking that authorization in real time
  4. Producing a tamper-proof record of what the agent did

Grantex fills this gap as an open, model-neutral, framework-agnostic protocol.


2. Definitions

TermDefinition
AgentAn AI-powered software process that takes autonomous actions on behalf of a Principal
PrincipalThe human user who authorizes an Agent to act on their behalf
DeveloperThe organization or individual who built and operates the Agent
ServiceAny API or platform that receives requests from an Agent
GrantA record of permission given by a Principal to an Agent for specific Scopes
Grant TokenA signed JWT representing a valid, non-revoked Grant
ScopeA named permission following the format resource:action[:constraint]
DIDDecentralized Identifier — the Agent's cryptographic identity
PolicyA rule that auto-approves or auto-denies an authorization before the consent UI is shown, evaluated by the Policy Engine
AnomalyA detected behavioral deviation from an agent's established activity baseline

3. Agent Identity

3.1 DID Format

Every Agent registered with a Grantex-compatible Identity Service receives a DID:

did:grantex:<agent_id>

Where <agent_id> is a ULID (Universally Unique Lexicographically Sortable Identifier).

Example: did:grantex:ag_01HXYZ123abcDEF456ghi

3.2 Identity Document

The DID resolves to an identity document containing:

{
  "@context": "https://grantex.dev/v1/identity",
  "id": "did:grantex:ag_01HXYZ123abcDEF456ghi",
  "developer": "org_yourcompany",
  "name": "travel-booker",
  "description": "Books flights and hotels on behalf of users",
  "declaredScopes": ["calendar:read", "payments:initiate:max_500"],
  "status": "active",
  "createdAt": "2026-02-01T00:00:00Z",
  "verificationMethod": [{
    "id": "did:grantex:ag_01HXYZ123abcDEF456ghi#key-1",
    "type": "JsonWebKey2020",
    "publicKeyJwk": { ... }
  }]
}

3.3 Key Management

  • Identity Services MUST use RS256 (RSA + SHA-256) for signing
  • Private keys MUST never leave the Identity Service
  • Public keys MUST be published at /.well-known/jwks.json
  • Key rotation MUST be supported without changing the DID

4. Scopes

4.1 Format

resource:action[:constraint]
  • resource — the data or service being accessed (e.g., calendar, payments, email)
  • action — the operation (e.g., read, write, send, initiate, delete)
  • constraint (optional) — a limiting parameter (e.g., max_500 for a spending limit)

4.2 Standard Scope Registry

ScopeDescription
calendar:readRead calendar events
calendar:writeCreate, modify, and delete calendar events
email:readRead email messages
email:sendSend emails on the Principal's behalf
email:deleteDelete email messages
files:readRead files and documents
files:writeCreate and modify files
payments:readView payment history and balances
payments:initiateInitiate payments of any amount
payments:initiate:max_NInitiate payments up to N in the account's base currency
profile:readRead profile and identity information
contacts:readRead address book and contacts

MPP Payment Scopes

ScopeDescription
payments:mpp:inferencePay for AI inference services via MPP
payments:mpp:computePay for compute services via MPP
payments:mpp:dataPay for data services via MPP
payments:mpp:storagePay for storage services via MPP
payments:mpp:searchPay for search services via MPP
payments:mpp:mediaPay for media services via MPP
payments:mpp:deliveryPay for delivery services via MPP
payments:mpp:browserPay for browser services via MPP
payments:mpp:generalPay for general services via MPP

4.3 Custom Scopes

Services MAY define custom scopes using reverse-domain notation:

com.stripe.charges:create:max_5000
io.github.issues:create

4.4 Scope Governance

Grantex maintains the canonical scope registry in §4.2 as normative. Implementations MUST support all standard scopes. Custom scopes MUST use reverse-domain notation. The Grantex working group governs additions to the standard registry.

4.5 Scope Display

Identity Services MUST maintain a human-readable description for each scope. Consent UIs MUST display human-readable descriptions, never raw scope strings.


5. Grant Flow

5.1 Overview

Developer App          Grantex                    Principal
     │                    │                           │
     │  POST /authorize    │                           │
     │  {agentId, scopes,  │                           │
     │   redirectUri}      │                           │
     │────────────────────►│                           │
     │                     │                           │
     │◄────────────────────│                           │
     │  {consentUrl}        │                           │
     │                     │                           │
     │  redirect user ─────────────────────────────►  │
     │                     │  consent UI displayed     │
     │                     │◄──────────────────────────│
     │                     │  Principal approves       │
     │                     │                           │
     │◄────────────────────────────────────────────────│
     │  redirectUri?code=AUTH_CODE                     │
     │                     │                           │
     │  POST /token        │                           │
     │  {code}             │                           │
     │────────────────────►│                           │
     │◄────────────────────│                           │
     │  {grantToken,        │                           │
     │   refreshToken}      │                           │

5.2 Authorization Request

POST /v1/authorize
Authorization: Bearer <api_key>
Content-Type: application/json

{
  "agentId": "ag_01HXYZ123abc",
  "principalId": "user_abc123",
  "scopes": ["calendar:read", "payments:initiate:max_500"],
  "expiresIn": "24h",
  "redirectUri": "https://yourapp.com/auth/callback",
  "state": "<csrf_token>",
  "audience": "https://api.targetservice.com"
}

audience is optional. When provided, it is embedded as the aud claim in the issued Grant Token (see §6.2). Services that accept tokens MUST reject tokens whose aud does not match their own identifier (§6.4).

Response:

{
  "authRequestId": "areq_01HXYZ...",
  "consentUrl": "https://consent.grantex.dev/authorize?req=eyJ...",
  "expiresAt": "2026-02-01T00:15:00Z"
}

5.3 Token Exchange

After Principal approves, Grantex calls redirectUri?code=AUTH_CODE&state=STATE.

POST /v1/token
Authorization: Bearer <api_key>
Content-Type: application/json

{
  "code": "AUTH_CODE",
  "agentId": "ag_01HXYZ123abc"
}

Response:

{
  "grantToken": "eyJhbGciOiJSUzI1NiJ9...",
  "refreshToken": "ref_01HXYZ...",
  "grantId": "grnt_01HXYZ...",
  "scopes": ["calendar:read", "payments:initiate:max_500"],
  "expiresAt": "2026-02-02T00:00:00Z"
}

6. Grant Token Format

6.1 Header

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "grantex-2026-02"
}

6.2 Payload

{
  "iss": "https://grantex.dev",
  "sub": "user_abc123",
  "aud": "https://api.targetservice.com",
  "agt": "did:grantex:ag_01HXYZ123abc",
  "dev": "org_yourcompany",
  "grnt": "grnt_01HXYZ...",
  "scp": ["calendar:read", "payments:initiate:max_500"],
  "iat": 1709000000,
  "exp": 1709086400,
  "jti": "tok_01HXYZ987xyz"
}

6.3 Custom Claims Reference

ClaimTypeDescription
agtstringAgent DID
devstringDeveloper org ID
grntstringGrant ID (for revocation lookup)
scpstring[]Granted scopes

6.4 Validation Rules

Services receiving a Grant Token MUST verify:

  1. Signature using the JWKS at iss/.well-known/jwks.json
  2. exp has not passed
  3. aud matches the service's identifier (if set)
  4. scp contains the required scopes for the requested operation
  5. (Online verification only) Token has not been revoked via the revocation endpoint

7. Revocation

7.1 Revoke a Grant

DELETE /v1/grants/{grantId}
Authorization: Bearer <principal_token>

Effect: all active tokens under this Grant are immediately invalidated. The Grant record is marked revoked with a timestamp.

7.2 Revoke a Specific Token

POST /v1/tokens/revoke
Authorization: Bearer <api_key>
Content-Type: application/json

{
  "jti": "tok_01HXYZ987xyz"
}

7.3 Online Revocation Check

POST /v1/tokens/verify
Authorization: Bearer <api_key>
Content-Type: application/json

{
  "token": "eyJhbGciOiJSUzI1NiJ9..."
}

Response:

{
  "valid": true,
  "grantId": "grnt_01HXYZ...",
  "scopes": ["calendar:read"],
  "principal": "user_abc123",
  "agent": "did:grantex:ag_01HXYZ123abc",
  "expiresAt": "2026-02-02T00:00:00Z"
}

7.4 Token Lifetime Guidance

Use CaseRecommended TTL
High-stakes actions (payments, send)1 hour
Standard agent tasks8 hours
Long-running background agents24 hours (max)

Refresh tokens are single-use and rotated on every refresh.

Implementations caching revocation state MUST NOT cache for longer than 5 minutes. High-stakes scopes (payments:initiate, email:send, files:write) SHOULD always use online verification.


8. Audit Trail

8.1 Log Entry Schema

{
  "entryId": "alog_01HXYZ...",
  "agentId": "did:grantex:ag_01HXYZ123abc",
  "grantId": "grnt_01HXYZ...",
  "principalId": "user_abc123",
  "developerId": "org_yourcompany",
  "action": "payment.initiated",
  "status": "success",
  "metadata": {
    "amount": 420,
    "currency": "USD",
    "merchant": "Air India"
  },
  "timestamp": "2026-02-01T12:34:56.789Z",
  "hash": "sha256:abc123...",
  "prevHash": "sha256:xyz789..."
}

8.2 Hash Chain

Each entry's hash is computed as:

SHA-256(entryId + agentId + grantId + action + status + timestamp + metadata_canonical + prevHash)

Fields are serialized as a canonical JSON object with keys sorted alphabetically. prevHash is null for the first entry in a chain. This makes any retrospective tampering detectable.

8.3 Log Action SDK Method

await grantex.audit.log({
  agentId: string,
  grantId: string,
  action: string,          // format: "resource.verb" e.g. "payment.initiated"
  status: 'success' | 'failure' | 'blocked',
  metadata?: Record<string, unknown>,
});

9. Multi-Agent Authorization

When Agent A spawns Agent B, B's Grant Token must chain back to the original Principal's authorization.

{
  "sub": "user_abc123",
  "agt": "did:grantex:ag_B_456",
  "parentAgt": "did:grantex:ag_A_123",
  "parentGrnt": "grnt_parentXYZ",
  "scp": ["email:read"],
  "delegationDepth": 1
}

Rules:

  • Sub-agent scopes MUST be a subset of the parent's scopes
  • delegationDepth is incremented at each hop
  • Implementations MUST enforce a developer-configurable delegation depth limit. The default RECOMMENDED limit is 3. Implementations MUST enforce a hard cap of 10.
  • The original Principal can revoke the root Grant to invalidate the entire chain

9.1 Delegation Endpoint

POST /v1/grants/delegate
Authorization: Bearer <api_key>
Content-Type: application/json

{
  "parentGrantToken": "eyJhbGciOiJSUzI1NiJ9...",
  "subAgentId": "ag_01HXYZ_sub",
  "scopes": ["email:read"],
  "expiresIn": "1h"
}

The server MUST:

  1. Decode and validate the parentGrantToken (signature and expiry are not re-verified server-side; revocation state is checked via Redis)
  2. Reject with 400 if the parent grant has been revoked
  3. Reject with 400 if any requested scope is not present in the parent token's scp claim
  4. Reject with 404 if subAgentId does not belong to the authenticated developer
  5. Compute expiry as min(parent token exp, now + expiresIn)

Response 201:

{
  "grantToken": "eyJhbGciOiJSUzI1NiJ9...",
  "grantId": "grnt_01HXYZ_sub",
  "scopes": ["email:read"],
  "expiresAt": "2026-02-01T01:00:00Z"
}

The issued grantToken carries parentAgt, parentGrnt, and delegationDepth = parentDepth + 1.

9.2 Cascade Revocation

Revoking a Grant via DELETE /v1/grants/:id MUST atomically revoke all descendant grants (grants whose parent_grant_id traces back to the revoked grant, at any depth). Implementations SHOULD use a recursive CTE or equivalent to traverse the delegation tree in a single database transaction.


10. Self-Hosting

10.1 Core Endpoints

All compliant Grantex implementations MUST expose the following endpoints:

EndpointDescription
POST /v1/agentsRegister agent
POST /v1/authorizeInitiate authorization
POST /v1/tokenExchange code for token
POST /v1/tokens/verifyVerify token online
POST /v1/tokens/revokeRevoke token
GET /v1/grantsList principal's grants
GET /v1/grants/:idGet a single grant
DELETE /v1/grants/:idRevoke grant (cascades to all descendants)
POST /v1/grants/delegateIssue a delegated sub-agent grant
POST /v1/audit/logWrite audit entry
GET /v1/audit/entriesQuery audit log
GET /v1/audit/:idGet a single audit entry
GET /.well-known/jwks.jsonPublic keys for offline verification
GET /healthHealth check

10.2 Optional Extensions

Minimal implementations MAY omit the following endpoints. Implementations that choose to support an extension MUST implement it as specified.

Policy Engine

EndpointDescription
POST /v1/policiesCreate a policy rule
GET /v1/policiesList policy rules
GET /v1/policies/:idGet a single policy rule
PATCH /v1/policies/:idUpdate a policy rule
DELETE /v1/policies/:idDelete a policy rule

Webhooks

EndpointDescription
POST /v1/webhooksRegister a webhook
GET /v1/webhooksList webhooks
DELETE /v1/webhooks/:idDelete a webhook

SCIM Tokens

EndpointDescription
POST /v1/scim/tokensCreate a SCIM Bearer token
GET /v1/scim/tokensList SCIM tokens
DELETE /v1/scim/tokens/:idDelete a SCIM token

SCIM 2.0

EndpointDescription
GET /scim/v2/ServiceProviderConfigSCIM capability discovery
GET /scim/v2/UsersList provisioned users
POST /scim/v2/UsersProvision a user
GET /scim/v2/Users/:idGet a provisioned user
PUT /scim/v2/Users/:idReplace a provisioned user
PATCH /scim/v2/Users/:idPartially update a provisioned user
DELETE /scim/v2/Users/:idDeprovision a user

SSO (OIDC)

EndpointDescription
POST /v1/sso/configConfigure SSO provider
GET /v1/sso/configGet SSO configuration
DELETE /v1/sso/configRemove SSO configuration
GET /sso/loginInitiate SSO login (redirects to IdP)
GET /sso/callbackOIDC callback handler

Anomaly Detection

EndpointDescription
POST /v1/anomalies/detectSubmit anomaly signal
GET /v1/anomaliesList detected anomalies
PATCH /v1/anomalies/:id/acknowledgeAcknowledge an anomaly

Compliance

EndpointDescription
GET /v1/compliance/summaryCompliance posture summary
GET /v1/compliance/evidence-packGenerate SOC2/GDPR evidence pack
GET /v1/compliance/export/grantsExport grant data
GET /v1/compliance/export/auditExport audit log

Billing

EndpointDescription
GET /v1/billing/subscriptionGet current subscription
POST /v1/billing/checkoutCreate a checkout session
POST /v1/billing/portalCreate a billing portal session

11. Policy Engine

11.1 Purpose

The Policy Engine evaluates rules against each authorization request before the consent UI is displayed. Policies enable developers to auto-approve routine, low-risk requests and auto-deny requests that violate organizational rules — reducing friction for Principals while maintaining control.

11.2 Effects

EffectDescription
auto_approveGrant is issued immediately without showing the consent UI
auto_denyAuthorization request is rejected immediately with a 403 response

11.3 Condition Fields

FieldTypeDescription
scopesstring[]Matches when the requested scopes are a subset of this list
principalIdstringMatches a specific Principal
agentIdstringMatches a specific Agent
timeWindowobjectTime-based constraint: { startHour, endHour, days[] } where days is an array of ISO weekday integers (1=Monday, 7=Sunday)

11.4 Evaluation Order

  1. Deny rules are evaluated first. The first matching auto_deny rule wins.
  2. Allow rules are evaluated next. The first matching auto_approve rule issues the grant.
  3. If no rule matches, the consent UI is shown to the Principal.

11.5 Example Policy

Auto-deny payment requests outside business hours:

{
  "name": "block-off-hours-payments",
  "effect": "auto_deny",
  "conditions": {
    "scopes": ["payments:initiate"],
    "timeWindow": {
      "startHour": 18,
      "endHour": 9,
      "days": [1, 2, 3, 4, 5]
    }
  }
}

11.6 CRUD API

POST   /v1/policies         — Create a policy rule
GET    /v1/policies         — List all policy rules
GET    /v1/policies/:id     — Get a single policy rule
PATCH  /v1/policies/:id     — Update a policy rule
DELETE /v1/policies/:id     — Delete a policy rule

12. Enterprise Identity — SCIM & SSO

12.1 SCIM 2.0 User Provisioning

Enterprises may sync users from their Identity Provider (Okta, Azure AD, etc.) into Grantex as Principals using the SCIM 2.0 protocol. The SCIM base path is /scim/v2/.

SCIM endpoints authenticate via a dedicated SCIM Bearer token, separate from developer API keys. This ensures that IdP provisioning credentials are isolated from application credentials.

SCIM token lifecycle:

POST /v1/scim/tokens
Authorization: Bearer <api_key>

Response:

{
  "token": "scim_...",
  "tokenId": "scimtok_01HXYZ...",
  "createdAt": "2026-02-01T00:00:00Z"
}

The token value is passed as Authorization: Bearer <scim_token> on all /scim/v2/* requests.

12.2 SSO (OIDC)

Developers may configure an OIDC-compliant Identity Provider to enable single sign-on.

Configure an IdP:

POST /v1/sso/config
Authorization: Bearer <api_key>
Content-Type: application/json

{
  "provider": "okta",
  "clientId": "...",
  "clientSecret": "...",
  "discoveryUrl": "https://dev-123.okta.com/.well-known/openid-configuration"
}

Login flow:

  1. Direct users to GET /sso/login — the auth service redirects to the IdP with a generated state and nonce.
  2. The IdP authenticates the user and redirects to GET /sso/callback.
  3. The callback validates the state (CSRF protection) and nonce (replay protection), then creates or updates the Principal record.

13. Anomaly Detection

13.1 Purpose

The Anomaly Detection system monitors agent behavior at runtime against each agent's established activity baseline. It identifies requests that deviate from normal patterns and surfaces them to developers for review.

13.2 Detection Trigger

After token issuance, the auth service emits an anomaly signal asynchronously. Anomaly detection MUST NOT block token issuance; it operates as an advisory layer only.

13.3 Anomaly Types

TypeDescription
unusual_scope_accessAgent requested scopes outside its typical pattern
high_frequencyToken issuance rate significantly exceeds the agent's baseline
off_hours_activityAgent activity detected outside the Principal's normal active hours
new_principalAgent is requesting access for a Principal it has never served before
cascade_delegationDelegation chain depth approaching or exceeding configured limits

13.4 Severity Levels

low | medium | high | critical

13.5 Acknowledge Workflow

Developers review and acknowledge anomalies to update the baseline and suppress repeat alerts:

PATCH /v1/anomalies/:id/acknowledge
Authorization: Bearer <api_key>
Content-Type: application/json

{
  "notes": "Authorized off-hours run for scheduled maintenance"
}

14. Security Considerations

  • Tokens MUST be signed with RS256. Symmetric algorithms (HS256) are NOT permitted.
  • Implementations MUST explicitly reject JWTs with alg: none. Both alg: none and HS256 MUST be rejected by all verifiers.
  • Token replay MUST be detectable via jti tracking.
  • Consent UIs MUST validate state parameter to prevent CSRF.
  • Redirect URIs MUST be pre-registered and exactly matched.
  • Services SHOULD implement online revocation checks for high-stakes operations.
  • Audit logs MUST be append-only at the API level (no update or delete endpoints).
  • SCIM endpoints MUST authenticate with a dedicated SCIM Bearer token, separate from developer API keys.
  • SSO callbacks MUST validate OIDC state and nonce parameters to prevent CSRF and replay attacks.
  • Policy engine MUST evaluate deny rules before allow rules to ensure restrictive policies are not bypassed.
  • Anomaly signals MUST NOT be used to synchronously block token issuance; the detection pipeline is advisory and asynchronous.
  • Consent UIs MUST display: agent name, developer name, all requested scopes with human-readable descriptions, token expiry, and a prominent deny/cancel action.

15. MPP Agent Passport

The Machine Payments Protocol (MPP) defines how AI agents pay for services via HTTP 402 flows. Grantex extends MPP with a verifiable identity layer via the AgentPassportCredential.

15.1 AgentPassportCredential

An AgentPassportCredential is a W3C Verifiable Credential (VC 2.0) that binds an agent's identity, human delegation, and MPP payment authorization into a single, offline-verifiable credential.

Type: ["VerifiableCredential", "AgentPassportCredential"]

Credential Subject fields:

  • id — Agent DID (did:grantex:ag_...)
  • type"AIAgent"
  • humanPrincipal — DID of the authorizing human
  • organizationDID — DID of the organization (did:web:<domain>)
  • grantId — Links to the underlying Grantex grant
  • allowedMPPCategories — Array of permitted MPP service categories (see §4.2 MPP Payment Scopes)
  • maxTransactionAmount{ amount, currency } ceiling per transaction
  • paymentRails — Array of payment networks (e.g., ["tempo"])
  • delegationDepth — Inherited from the grant's delegation chain (§9)
  • parentPassportId — (Optional) For delegated sub-agent passports

Revocation: Uses StatusList2021 (existing infra). Revoking a passport flips the corresponding bit.

Maximum expiry: 720 hours (30 days).

15.2 MPP Header Convention

Agents attach passports to outgoing MPP requests via the X-Grantex-Passport HTTP header:

X-Grantex-Passport: <base64url-encoded-credential>

15.3 Merchant Verification Algorithm

  1. Decode base64url → parse JSON → validate W3C VC 2.0 structure
  2. Check issuer against trusted issuers list
  3. Check validUntil > now
  4. Resolve issuer DID document → fetch JWKS → verify Ed25519/RS256 signature
  5. (Optional) Check revocation via StatusList2021
  6. Validate allowedMPPCategories includes the requested service category
  7. Validate maxTransactionAmount.amount >= transaction amount
  8. Return VerifiedPassport with extracted identity fields

Target: <50ms on warm JWKS cache.

15.4 Trust Registry

A public registry mapping organization DIDs to verified trust records. Each record includes:

  • organizationDID — e.g., did:web:acme.com
  • verificationMethoddns-txt | manual | soc2
  • trustLevelbasic | verified | soc2
  • domains — Verified domain list

Endpoint: GET /v1/trust-registry/:orgDID (public, no auth required).


Protocol Design Decisions

The following design questions that were open in v0.1-draft have been resolved for v1.0: Scope standardization — Grantex maintains a normative canonical scope registry (§4.2), governed by the Grantex working group; custom scopes must use reverse-domain notation. Cross-chain identity — Agent DIDs are scoped to the issuing Grantex-compatible implementation and are not required to be portable across implementations in v1.0. Offline revocation — Implementations caching revocation state MUST NOT cache for longer than 5 minutes (§7.4). Delegation depth — The protocol mandates a developer-configurable limit with a recommended default of 3 and a hard cap of 10 (§9). Consent UI requirements — Compliant consent UIs MUST display agent name, developer name, all requested scopes with human-readable descriptions, token expiry, and a prominent deny/cancel action (§14).


Changelog

VersionDateNotes
1.0Feb 2026Final. §11 Policy Engine, §12 Enterprise Identity (SCIM/SSO), §13 Anomaly Detection; expanded §10 endpoint table with Core vs. Optional Extensions; resolved all open design questions; specification frozen.
0.1-draft rev 2Feb 2026Add audience to §5.2; add status to §8.2 hash formula; add §9.1 delegation endpoint and §9.2 cascade revocation; expand §10 endpoint table
0.1-draftFeb 2026Initial draft — seeking community feedback

Grantex Protocol Specification is licensed under Apache 2.0