@solidus-network/agent-identity
v0.1.6
Published
Portable, verifiable, revocable identity for AI agents — did:solidus DIDs (registered in the W3C DID Method Registry), BBS+ selective-disclosure credentials, and ERC-8004 passport anchoring. Testnet-grade; external audit pending.
Maintainers
Readme
@solidus-network/agent-identity
Portable, verifiable, revocable identity for AI agents:
- a
did:solidusDID scoped to the agent (not the operator), - an ERC-8004 Identity Registry passport (ERC-721) anchored to that DID on an L2,
- BBS+ selective-disclosure credentials (owner-binding, capability-scope, spend-mandate),
- offline hot-path verification via the sibling
@solidus-network/agent-identity-verifypackage.
Solidus integrates ERC-8004 (an open EIP backed by MetaMask, Google, Coinbase, OriginTrail and the EF) — Solidus is the credential issuer behind the passport, not the passport standard. Operator KYC is inherited from verify.solidus.network; this SDK consumes it, it never performs KYC.
Status — read this first
- Solidus L1 is testnet-only. DIDs resolve as
did:solidus:testnet:<addr>. There is no mainnet. The testnet resets daily — DIDs and credentials created on it are wiped at the next reset, so treat everything below as a live sandbox, not durable storage. - The hosted issuance backend is LIVE at
https://agents.solidus.network(since 2026-07-13).registerOperatorandcreateAgentwork today:createAgentreturns an activedid:solidus:testnet:…that resolves on the public RPC. - ⚠ THE TESTNET IS WIPED EVERY NIGHT AT ~04:03 UTC. This is not a figure of speech: a scheduled job deletes the chain's entire datadir. Every agent DID and credential issued during the day is destroyed and stops resolving. Treat anything you create here as lasting hours, not days. We are fixing the cause; until this line disappears from this README, assume it is still true.
did:solidusis registered in the W3C DID Method Registry (w3c/did-extensions#713, merged 2026-07-04). Registration records that a method exists and is documented; it is not a W3C endorsement and says nothing about whether this implementation is secure — see the two lines around it.- BBS+ signing is testnet-grade. External audit pending (NLnet NGI Zero, H2 2026 target). Do not protect production-grade value with it yet.
- ERC-8004 anchoring targets Base Sepolia during development. Passports are anchoring:
createAgentmints an ERC-721 in the official Identity Registry (first anchors landed 2026-07-13, e.g. tokenId 8066 — checkownerOfyourself on any Base Sepolia RPC). The relayer's gas balance is low; if it drains before the next top-up, new anchors queue and the agent'spassportstaysnulluntil it refills. - Credentials issue UNANCHORED for now: the Solidus testnet chain does not yet accept the agent credential types, so
issueCredentialreturns a fully signed BBS+ bundle whose VC proof saysanchor: unanchoredinstead of carrying an L1 credential id. Offline verification and status-list revocation work exactly the same; on-chain anchoring resumes when the chain adds the types. - The API hostnames (
agents,broker,rpc) are served directly, without a bot-challenge layer — resolved 2026-07-14 after datacenter/VPS clients were briefly hit by a Cloudflare browser challenge. If you saw HTTP 403 "Just a moment…" from a cloud box before that date, retry; it was the edge, not the service.
Install
npm i @solidus-network/agent-identityWhat works today (no backend)
Everything in this section runs right now, against public endpoints only.
Resolve any did:solidus DID
import { createAgentIdentity } from '@solidus-network/agent-identity'
const solidus = createAgentIdentity({ baseUrl: 'https://agents.solidus.network' })
const doc = await solidus.resolveDid('did:solidus:testnet:<addr>')
// → { id, controller, active } | nullOr from any machine with nothing but curl:
curl -s -X POST https://rpc.solidus.network \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"solidus_didResolve","params":["did:solidus:testnet:<addr>"]}'Create an agent DID directly on the testnet (fee-exempt)
You can also create the DID without the hosted backend, straight against the chain, with @solidus-network/sdk. Install it and the key library explicitly (both are dependencies of this package, but package managers with isolated node_modules — pnpm, Yarn PnP — won't let you import transitive dependencies). Pin @noble/ed25519 to v2 — the example uses the v2 API, which is what these packages ship with; v3 renamed it:
npm i @solidus-network/sdk @noble/ed25519@2DidCreate is fee-exempt on the Solidus testnet for a fresh key — no funding, no faucet:
import * as ed from '@noble/ed25519'
import { createSdk } from '@solidus-network/sdk'
const priv = Buffer.from(ed.utils.randomPrivateKey()).toString('hex')
const pub = Buffer.from(await ed.getPublicKeyAsync(priv)).toString('hex')
const sdk = createSdk({ mode: 'testnet', rpcUrl: 'https://rpc.solidus.network', signerPrivateKey: priv })
const did = await sdk.did.create(pub) // → { id: 'did:solidus:testnet:…', … }
const doc = await sdk.did.resolve(did.id) // full W3C DID document
await sdk.did.deactivate(did.id, priv) // revocable — resolves to null afterwards(Keep the private key: deactivation requires the signer. On sdk 0.6.1+, an immediate deactivate after create retries a stale-nonce failure automatically; on 0.6.0, if it fails with invalid nonce, retry after a couple of seconds.)
Verify credentials offline
Selective-disclosure proof verification runs entirely offline — see @solidus-network/agent-identity-verify for the gateway/middleware verifier, and this package's deriveCredentialProof and buildAgentAuthHeader / buildMandateHeader exports for the holder side.
Quickstart — hosted backend (LIVE at https://agents.solidus.network)
The full flow against the live default endpoint:
import { createAgentIdentity } from '@solidus-network/agent-identity'
const solidus = createAgentIdentity({ baseUrl: 'https://agents.solidus.network' })
// One-time: register as an operator. Agent creation requires a KYC
// credential ref from verify.solidus.network (assurance inherited, not re-run).
await solidus.registerOperator({
kyc: { credentialRef: 'urn:solidus:credential:…', assuranceLevel: 'substantial' },
})
const agent = await solidus.createAgent({ capabilities: ['browse'] })
// → { did: 'did:solidus:testnet:…', status: 'active', custody: 'managed', … }Key custody
managed(default) — the backend mints a fresh Ed25519 keypair for the agent and escrows it encrypted. Export it any time:const { privateKey } = await solidus.exportAgentKey(agent.id)byo— you hold the key. The DidCreate transaction is built and signed locally; only the signed transaction is relayed. The chain enforces that the transaction signer owns the registered key, so the backend physically cannot register a key it doesn't hold:const agent = await solidus.createAgent({ custody: 'byo', signerPrivateKey })
Trust boundary
This package is open source end-to-end and holds no issuer keys. Credential signing (BBS+ issuer, did:solidus issuer, ERC-8004 relayer) happens only in the Solidus backend — trust in a credential is trust in the issuer key, not in this code. The issuer's public keys (BBS+ BLS12-381 G2 + the Ed25519 key that signs status lists) are published at GET https://agents.solidus.network/ — pin them in your verifier.
License
Apache-2.0
