Everything so far has been running onDocumentation Index
Fetch the complete documentation index at: https://docs.getbindu.com/llms.txt
Use this file to discover all available pages before exploring further.
localhost. The agents accept unsigned requests because "auth": { "type": "none" } tells the gateway not to sign them. That’s fine for development - there’s no attacker between you and your own laptop.
The fix is: the gateway gets a cryptographic identity and signs every outbound request. Agents verify the signature before processing. If an attacker tries to forge a request, the signature won’t match the gateway’s registered public key, and the agent rejects the call.
What’s a DID?
DID stands for Decentralized Identifier. It’s a string that looks like:.well-known URL).
You sign outbound requests with the private key. Recipients verify with the public key. Standard public-key cryptography - what puts the green lock in your browser.
The three env vars
Generate a private key seed (once, keep it secret):gateway/.env.local:
gateway/.env.local
Hydra - the registration server
Ory Hydra is an open-source OAuth 2.0 / OIDC server. You run your own Hydra (or share one with your peers) — there is no Bindu-hosted public Hydra. The gateway integrates with whichever Hydra you point it at.How it works: the gateway registers itself as an OAuth client at boot using its DID as the
client_id and a secret derived deterministically from the seed. The registry stores your DID + public key in the client’s metadata; agents that want to verify your signatures fetch your /.well-known/did.json.gateway/.env.local
Partial Hydra config fails fast. Both URLs must be set together, or neither. If you set only one, the gateway aborts boot with the error
Partial Hydra config — set both or neither.npm run dev. You’ll now see:
The gateway derived a DID and public key from your seed.
Deterministic - same seed always produces the same DID.
It POSTed to Hydra's admin API to register.
As an OAuth client, with its DID as the
client_id and its public key in the metadata. Idempotent - safe to restart as many times as you like.It wired up a client-credentials token provider.
The first call to a
did_signed peer triggers an OAuth client_credentials exchange against BINDU_GATEWAY_HYDRA_TOKEN_URL; the resulting access token is cached in memory and proactively refreshed 30 seconds before expiry. Concurrent callers during a refresh share the same in-flight fetch — Hydra is hit at most once per refresh window.http://localhost:3774/.well-known/did.json. Curl it:
Flipping a peer to signed mode
Change the/plan request:
No
token or envVar on auth — the gateway will use its own Hydra token automatically. The optional trust block is a separate decision: it tells the gateway to verify incoming signatures from this peer (and, if pinnedDID is set, to reject responses signed by any other key). You can sign outbound without verifying inbound, or verify inbound without signing outbound — they’re independent.Body signed
The gateway wraps the serialized JSON-RPC body in
{"body": <body>, "did": <gateway DID>, "timestamp": <unix seconds>} and serializes that envelope with a Python-compatible sorted-keys serializer (matches the reference agent’s json.dumps(payload, sort_keys=True) byte-for-byte, spaces and all — see gateway/src/bindu/identity/local.ts). Those exact UTF-8 bytes are then signed with the gateway’s Ed25519 private key.Three signing headers attached
X-DID (your gateway’s DID), X-DID-Signature (base58 Ed25519 signature), and X-DID-Timestamp (unix seconds) go on every signed call.OAuth token attached
Authorization: Bearer <token> — the cached client-credentials token from Hydra. Auto-refreshed 30s before expiry.Resolves the caller's DID to a public key.
Via the gateway’s
/.well-known/did.json or a cached DID→key mapping.Verifies the X-DID-Signature against the request body.
Using the gateway’s public key (
Ed25519VerificationKey2020, base58-encoded in the DID document’s authentication block).Two modes: auto vs manual
- Auto mode (default)
- Manual mode (federated)
One Hydra, shared by the gateway and its peers, handles all the registration and token exchange.Request side:Use this unless you have a specific reason not to.
gateway/.env.local
Chapter takeaway
Local dev
Keep
auth.type: "none". No cryptography needed.Anything across a network you don't control
Configure the DID identity and flip peers to
did_signed. The token and signature are automatic once the env vars are set; you never touch crypto code.