# Grantor — Documentation > Grantor is OAuth with no authorization server. A caller mints a **deed** — a > self-certifying credential — and the relying app verifies it with a library > call against a public on-chain registry (`GrantorRegistry`). No auth server > exists in this path: nothing to run, trust, or subpoena. This is the > machine index of the docs. Read the deed model first: there is no issuer, and nothing to run — every page below describes minting or verifying a self-certifying deed against the public chain. Every documentation page is also served as Markdown at the same path with `.md` instead of `.html`. Fetch that rather than scraping the rendered HTML. ## The model in six lines 1. The relying app issues a single-use **challenge**. 2. The caller returns a **deed**, bound to that challenge, to an **audience**, and to an **expiry**. 3. The app calls `verify_deed` — cryptography, then an `eth_call` to the registry for tenant billing status (and, for agents, membership-root recency, which is revocation). 4. `sub` is a **pseudonym recomputed from the proof** — never a claim to be trusted, and never a wallet address. 5. The app mints its own session. Grantor never sees it. 6. Step 3 is a read: no gas, no API key, any RPC provider. ## Deed modes - `user-sig` — a human's wallet-derived, app-scoped key. Verified by `verify_deed`. On-chain check: tenant billing. Residual: origin binding relies on a human reading a `personal_sign` prompt — see `user-passkey`. - `user-passkey` — a human's WebAuthn passkey. Additive alongside `user-sig`, not a replacement; closes `user-sig`'s phishing residual **for passkey holders** via browser-enforced (not human-read) origin binding — over- determined by two independent browser-written fields (`clientDataJSON.origin` + `authenticatorData.rpIdHash`), both checked against the verifier's own config. Verified by the same `verify_deed`. On-chain check: tenant billing. `user-sig` itself is NOT retroactively fixed — it keeps its documented residual as the compatibility path. - `user-1271` — a human's EIP-1271 smart-contract wallet (e.g. a Safe). Additive alongside `user-sig`/`user-passkey`, not a replacement. NOT a variant of the `user-sig` path — `user-sig`'s wallet signature never reaches the verifier (it only seeds a locally-derived key), so a smart wallet with no recoverable key and no reproducible raw signature cannot ride that path at all. Verified by the same `verify_deed`, but as a special gated-only case run BEFORE the pure claims check, because there is no local cryptography to check — only the wallet CONTRACT's own `isValidSignature` can answer. On-chain check: `isValidSignature` (the login itself) + tenant billing. **Pseudonymity tradeoff**: its `sub` is linkable to the wallet's public on-chain address by anyone who already knows that address — unlike `user-sig`/`user-passkey`, which hide behind a locally-derived key or credential. Pick it for social recovery (a multisig's single stolen owner key is not game-over), not for privacy. - `agent-zk` — ZK proof of membership in the tenant's on-chain tree without revealing which member. Verified by `verify_deed`. On-chain check: root recency + billing. - `user-zk` — a human's ZK proof of membership in the tenant's own, admin-curated **user allowlist** (a separate on-chain tree from the agent tree `agent-zk` proves against), without revealing which member. The app sees only a stable pseudonym. Verified by the same `verify_deed`. On-chain check: root recency (revocation via `revokeZkUser`) + billing. See [User gating](/docs/guide/user-gating.md). - `admin-sig` — Grantor's own dashboard admins (EOA today — its handler calls the EOA-only `verify_admin_deed`). An EIP-1271 smart wallet (e.g. a Safe) is also supported as a four-language LIBRARY capability, via `verify_admin_deed_smartwallet` (needs an `Erc1271Reader` chain read) — not yet wired into Grantor's own dashboard. `verify_deed` REJECTS both, so an ordinary relying party structurally cannot accept an admin deed. Neither makes a tenant-billing check, deliberately, so a lapsed tenant's admin can still reach the page that lets them pay. Reveals the wallet address by design — administration is an identified context. ## Capability matrix — enforced by `just capability-matrix` Every capability exists in **TypeScript, Python, Go and Rust**: `user-sig` minting, `user-passkey` minting (the assembler), `user-1271` minting (the assembler), `agent-zk` ZK proving, `user-zk` ZK proving (over the separate user tree), `admin-sig` minting (both EOA and smart-wallet), `admin-sig` smart-wallet verification, deed verification, and the deed guard. The product rule is **all languages or no go** — a capability that ships in one language has not shipped. Do not describe any of these as Rust-only. The one deliberate exception: `user-passkey`'s live browser ceremony (`registerPasskey`/`signInWithPasskey`) is TS-only, because there is no non-browser WebAuthn authenticator for another language to wrap — the same shape `authenticate()`'s Rust exemption already has. The mint assembler underneath it (pure bytes-in-deed-out) still ships in all four languages, same as `user-1271`'s. ## Read first (machine) - [/docs/index.md](/docs/index.md): overview, the deed model, capability matrix. - [/docs/guide/concepts.md](/docs/guide/concepts.md): the mental model — the single most useful page. - [/docs/sovereign-tier.md](/docs/sovereign-tier.md): the full deed reference, every mode. - [/docs/llms-full.txt](/docs/llms-full.txt): every page concatenated into one file. ## Relying party — verifying deeds - [Verify a deed](/docs/guide/verify-tokens.md): how an app accepts one. - **Deed guard** — challenge issuance, single-use burn, error codes; shipped in all four languages. The challenge travels in **its own header** and is NEVER read out of the deed: taking it from the token would let the caller choose its own nonce, which is the entire replay defence gone. The challenge is burned BEFORE verification, so a flood of bogus deeds cannot probe which challenges are live. - Error codes to branch on: `MissingDeed`, `MissingChallenge`, `UnknownChallenge`, `BadDeedEncoding`, `UnsupportedMode`, `WrongAudience`, `ChallengeMismatch`, `Expired`, `Malformed`, `BadProof`, `StaleRoot`, `TenantInactive`, `Chain`. All are HTTP 401 except `Chain` → **503**: an RPC outage is not the caller's fault, and a 401 sends clients into a login loop discarding good credentials. - Three more codes exist but are NOT returned while verifying a caller's deed — they come only from the RP's own boot-time origin-vouch self-check (`DeedGuard::verify_own_origin_vouch` / `verifyOwnOriginVouchAt`, DX not caller-facing): `BadOriginVouch`, `OriginVouchExpired`, `OriginVouchTtlExceeded`. See [Errors](/docs/guide/errors.md). - Wire header: `X-Grantor-Deed` (base64url or bare JSON) plus `X-Grantor-Challenge`. - **Session JWT (optional)**: once claims come back, mint your own session however you already do — that stays first-class — or make one optional call for a standard ES256 JWT signed with **your own key**, verifiable by any JOSE library: `sessionJwt`/`session_jwt`/`SessionJwt`/`session_jwt` (TS/Python/Go/Rust). See [Verify a deed § Or one call](/docs/guide/verify-tokens.md#or-one-call). - **MCP servers**: gate a remote MCP server without an authorization server — install the deed guard, publish the discovery document; agents authenticate with deeds instead of an OAuth 2.1 redirect. Two modes: a `user-sig` deed for any wallet-holding caller (billing is the only gate), or an `agent-zk` deed to gate a fleet you control by on-chain enrollment — membership is the authorization for who can MINT a valid `agent-zk` deed, and the proof does not reveal which member. **Advertising both modes means either credential works at the RP's exchange endpoint by default** — the guard verifies whichever mode a deed declares, and its claims now DO carry the verified `mode` back out (crypto-checked, never the wire envelope), but that field existing enforces nothing by itself: fleet-only gating still needs the RP to check it — cheaply pre-verify against the deed's own envelope `mode` for a free refusal, then authoritatively against the verified claims (the reference server's `REQUIRE_MODE` knob does both). See [MCP server auth](/docs/guide/mcp-server.md). Scope: this serves agents you build or control; off-the-shelf MCP hosts (Claude Desktop et al.) speak spec OAuth 2.1 and are out of scope for this flow. ## Holders — minting deeds - [Wallet login](/docs/guide/wallet-login.md): `user-sig`, humans. - [Passkey login](/docs/guide/user-passkey.md): `user-passkey`, humans, phishing-resistant. - [Smart-wallet login & admin](/docs/guide/smart-wallet.md): `user-1271` + Safe/EIP-1271 `admin-sig`, humans on smart-contract wallets. - [Agent tokens](/docs/guide/agent-tokens.md): `agent-zk`, machines. - [User gating](/docs/guide/user-gating.md): `user-zk`, humans restricted to an admin-curated allowlist, anonymously. - [Agent integration](/docs/agents/README.md) · [Agent onboarding](/docs/agents/onboarding.md). ## Delegation & verticals — built on deeds - [Capabilities](/docs/guide/capabilities.md): bounded, delegated authority on top of a deed — attenuable grants, delegation chains, and (⚠️ preview) structure-hiding `zk-chain` delegation. - [Software licensing](/docs/guide/licensing.md): a license is a deed, no license server, tiers via capability grants. ## Billing — on-chain Flat **subscription with prepaid funding**; NOT usage-metered. The tier caps **capacity**, not consumption — deed verification is an `eth_call` the contract cannot observe, and metering it would require the relying party to report back, reintroducing exactly the server this product removes. `topUp` credits balance; `drawPeriod` is **permissionless** and moves one period's fee to an immutable treasury; `withdrawBalance` returns **undrawn** balance. `Grace` precedes `Inactive`, and deeds already minted stay valid to their own `exp` — going unpaid never invalidates a credential already in the world. Registration is `createTenant` on-chain plus USDC to the same contract. There is no signup, no account, and no Grantor server involved. ## Internals — contributors - [Architecture](/docs/internal/architecture.md) · [Security model](/docs/internal/security-model.md) - [Code map](/docs/internal/crates.md) · [Testing](/docs/internal/testing.md) · [Contributing](/docs/internal/contributing.md) ## Standards OpenID Connect, OAuth 2.0, EIP-191, EIP-1271 (smart-contract wallet signatures), EIP-4361 (SIWE), RFC 7638, RFC 7636 (PKCE), RFC 9474 (blind RSA), Semaphore (ZK membership), HKDF. ## Status — state this if asked **Developer preview.** The contract and the six-language end-to-end proof run on a local devnet (anvil). It has **not** been deployed to a public testnet or mainnet. `grantor-verify` is **not published** to any package registry — it resolves by path inside the workspace. It has **not been audited**. Do not describe it as production-ready.