TypeScript packages for building on the Solidus Network — a blockchain protocol for decentralized identity and verifiable credentials.
Published to npm under the @solidus-network scope. Versions in the badges are live from the registry — this page does not restate them, because a number typed into prose goes stale the day after you type it.
| Package | npm | Description |
|---|---|---|
@solidus-network/sdk |
Main SDK — DID resolution + rotation, credential issuance/verification, SD-JWT VC (incl. KB-JWT, status list, nested-path disclosure), on-chain queries | |
@solidus-network/auth |
DID-based authentication primitives — Ed25519 challenge, W3C VP verification | |
@solidus-network/types |
Shared TypeScript types — DIDs, Verifiable Credentials (Data Model 2.0), auth challenges | |
@solidus-network/bbs |
BBS+ selective-disclosure primitives — draft-irtf-cfrg-bbs-signatures, BLS12-381 SHA-256, byte-compatible with the on-chain implementation |
Portable identity for AI agents. Built on the core above; you do not need these to issue or verify human credentials. Source lives in the Solidus monorepo, not this repo.
| Package | npm | Description |
|---|---|---|
@solidus-network/agent-identity |
did:solidus DIDs, BBS+ selective-disclosure credentials, and ERC-8004 passport anchoring for AI agents | |
@solidus-network/agent-identity-verify |
Hot-path verifier — offline BBS+ proof verification plus a cached, fail-closed OAuth Status List revocation check | |
@solidus-network/agent-identity-react |
React components — the Verified-by-Solidus badge, agent passport card, mandate-approval prompt |
Browser-side document capture, used by Solidus Verify. Source lives in the monorepo, not this repo.
| Package | npm | Description |
|---|---|---|
@solidus-network/capture |
Embeddable web ID-capture SDK — guided camera capture with quality gating and on-device MRZ/barcode extraction | |
@solidus-network/id-extract |
Client-side (WASM) extraction — barcode read, MRZ OCR, checksum reconstruction, confidence gate. Framework-free |
Source lives in the monorepo, not this repo.
| Package | npm | Description |
|---|---|---|
@solidus-network/wallet |
Wallet SDK — did:solidus keypair derivation, injectable credential store, BBS+ selective-disclosure presentation, scoped payment-mandate stamping | |
@solidus-network/mcp |
MCP server — run-time agent tools: resolve did:solidus, verify credentials, check/create scoped spend mandates, authorize payments against them | |
@solidus-network/auth-otp |
Provider-agnostic OTP (SMS/email) login core — injected clock, rng, store, sender and identity resolver; the caller owns session issuance and delivery | |
@solidus-network/cli |
CLI — wire did:solidus, verify and agent identity into your app in one command |
npm install \
@solidus-network/sdk \
@solidus-network/auth \
@solidus-network/types \
@solidus-network/bbsimport { createSdk } from '@solidus-network/sdk'
// Config is flat — there is no `chain` wrapper.
const solidus = createSdk({
mode: 'testnet',
rpcUrl: 'https://rpc.solidus.network',
signerPrivateKey: process.env.SOLIDUS_SIGNER_KEY,
})
// Resolve a DID. Returns null when the DID is unknown or deactivated.
const didDocument = await solidus.did.resolve('did:solidus:testnet:abc123')
// Spec-conformant W3C DID Resolution — distinguishes "not found" from
// "deactivated" instead of folding both into null. Chain mode only, so it is
// optional on the SDK surface and `undefined` in stub mode. Guard it.
if (solidus.did.resolveWithMetadata) {
const { didDocument, didDocumentMetadata } =
await solidus.did.resolveWithMetadata('did:solidus:testnet:abc123')
}
// Issue a W3C VC 2.0 credential (as an authorised issuer)
const vc = await solidus.credentials.issue({
subjectDid: 'did:solidus:testnet:xyz789',
issuerDid: 'did:solidus:testnet:issuer1',
issuerPrivateKey: process.env.SOLIDUS_ISSUER_KEY!,
type: ['VerifiableCredential', 'KYCVerified'],
claims: { country: 'US', tier: 'standard' },
expiresInDays: 365,
})import { issueSdJwtVc, presentSdJwtVc, verifySdJwtVc } from '@solidus-network/sdk'
// Ed25519 keys are raw bytes — Uint8Array, not hex strings and not JWKs.
declare const issuerPrivateKey: Uint8Array, issuerPublicKey: Uint8Array
declare const holderPrivateKey: Uint8Array, holderPublicKey: Uint8Array
// Anything NOT listed in `disclosable` is always visible to the verifier, so
// list every claim the holder should be able to withhold.
const issued = await issueSdJwtVc({
issuer: 'did:solidus:testnet:issuer1',
vct: 'https://example.com/credentials/age',
subject: { given_name: 'Ada', birth_date: '1990-01-01' },
disclosable: ['given_name', 'birth_date'],
issuerPrivateKey,
holderPublicKey, // binds the credential to this holder, enabling the KB-JWT
})
// Holder reveals birth_date and withholds given_name. The Key-Binding JWT ties
// that disclosure to one verifier and one nonce, so it cannot be replayed.
const presentation = await presentSdJwtVc({
compact: issued.compact,
claimsToReveal: ['birth_date'],
audience: 'https://verifier.example',
nonce: 'abc',
holderPrivateKey,
})
// The verifier supplies the issuer's public key itself — resolve it from the
// issuer DID (`solidus.did.resolve`) and apply your own trust policy.
const result = await verifySdJwtVc({
compact: presentation.compact,
issuerPublicKey,
expectedAudience: 'https://verifier.example',
expectedNonce: 'abc',
})The API is class-based. Messages and headers are raw bytes; utf8() encodes them.
import { BbsSecretKey, utf8 } from '@solidus-network/bbs'
const messages = ['name=Ada', 'over18=true', 'birth_date=1990-01-01'].map(utf8)
const header = utf8('solidus-kyc-v1')
// Issuer signs the whole message set once
const sk = await BbsSecretKey.generate()
const pk = await sk.publicKey()
const signature = await sk.sign(header, messages)
// Holder discloses only "over18=true" (index 1) — the rest stay hidden.
// The presentation header binds the proof to one verifier challenge.
const presentationHeader = utf8('verifier-nonce')
const proof = await signature.createProof({
pk,
header,
presentationHeader,
messages,
disclosedIndices: [1],
})
// The verifier never sees name or birth_date — only what was disclosed
const ok = await proof.verify({
pk,
header,
presentationHeader,
disclosedIndices: [1],
disclosedMessages: [messages[1]],
})import { createChallenge, verifyPresentation } from '@solidus-network/auth'
import type { VerifiablePresentation } from '@solidus-network/auth'
// Holder DID, then a time-to-live in seconds
const challenge = createChallenge('did:solidus:testnet:abc123', 300)
// The client signs challenge.nonce and returns a W3C Verifiable Presentation
declare const presentation: VerifiablePresentation
// Resolve the holder's Ed25519 public key from the VP's verificationMethod id
declare const getPublicKey: (verificationMethodId: string) => Promise<Uint8Array>
// Three positional arguments, in this order — not one options object
const result = await verifyPresentation(challenge, presentation, getPublicKey)stub— local Postgres-backed mock for development; no chain interaction.testnet— talks to the Solidus testnet via JSON-RPC atrpc.solidus.network.mainnet— reserved for the post-audit launch.
- SDK docs: https://docs.solidus.network/sdk
- Guides: https://docs.solidus.network/guides (Express, Next.js, KYC integration, webhooks)
- API reference: https://docs.solidus.network/api
- Whitepaper: https://docs.solidus.network/resources/whitepaper
did:solidusmethod spec: https://github.com/solidusnetwork/did-solidus-spec/blob/v0.1.0/SPEC.md
- Testnet RPC: https://rpc.solidus.network
- Explorer: https://explorer.solidus.network
- Status: https://solidus.network
Apache-2.0 — see LICENSE (each published package ships its own copy).