UDDI is an alpha-stage framework for building decentralized digital identity systems. It combines DID-style identifiers, Ed25519 signatures, Verifiable Credential primitives, a TypeScript SDK, a Go API gateway, and early zero-knowledge proof circuits.
The repository is currently a framework foundation, not a production network. The implemented pieces are usable for local development and contract testing; blockchain persistence, production ZKP proving, mobile wallet flows, and mainnet/testnet operations are still roadmap items.
Implemented today:
- TypeScript monorepo using pnpm workspaces.
@uddi/coreidentity generation, DID derivation, message signing, DID documents, and Verifiable Credential signing/verification.@uddi/sdkclient/verifier SDK surface for identity creation, auth challenges, proof requests, DID resolution, and claim verification calls.- Go API gateway with testable router, DID register/resolve/revoke endpoints, API key middleware, auth challenge generation, Ed25519 auth presentation verification, replay protection, and timestamp/service binding checks.
- DID storage abstraction in the API, with memory and Postgres-backed implementations.
- Credential registry abstraction in the API, with memory and Postgres-backed implementations.
- API-side Ed25519 Verifiable Credential proof verification for credential issue and status verification.
- Challenge storage abstraction in the API, with memory and Redis-backed implementations.
- API key validation with memory and Postgres-backed stores, including seeded development credentials.
- Admin API key management for creating, listing, and revoking service API keys.
- API hardening middleware for security headers, request body limits, and per-IP rate limiting.
- Observability endpoints for liveness, readiness, JSON metrics, and structured request logs.
- Versioned Postgres schema migrations for DID, API key, and credential tables.
- DID/VC structural compliance baseline tests in
@uddi/core. - Circom circuit drafts for age and citizenship verification.
- CI workflow for TypeScript and Go checks, with Rust/Docker jobs gated until those packages exist.
Not implemented yet:
- Substrate/Rust blockchain node and pallets.
- Full W3C DID/VC compliance test suite.
- Production API key management.
- Real ZKP prover/verifier service runtime.
- Mobile identity wallet.
- W3C DID/VC full compliance test suite.
- Public testnet/mainnet.
| Package | Status | Description |
|---|---|---|
@uddi/core |
Implemented alpha | Core identity, DID, signing, and VC primitives. |
@uddi/sdk |
Implemented alpha | Developer SDK for holder and verifier flows. |
packages/api |
Implemented alpha | Go REST API gateway with DID registry storage and auth verification. |
packages/zkp |
Circuit drafts | Circom circuits for age and citizenship proofs. |
packages/blockchain |
Roadmap | Planned Substrate blockchain node and pallets. |
packages/mobile |
Roadmap | Planned mobile wallet application. |
Requirements:
- Node.js 22.13 or newer
- Corepack
- Go 1.25.x for the API package
Install dependencies:
corepack enable pnpm
pnpm installCopy the example environment file when you want to run the API locally outside Docker:
cp .env.example .envRun TypeScript checks:
pnpm -r build
pnpm -r test
pnpm -r lintPreview npm package contents:
pnpm pack:dry-runCreate a release candidate tag:
git tag v0.1.0-alpha.1
git push origin v0.1.0-alpha.1Release tags run GitHub validation and create a draft GitHub Release.
Run Go API checks:
cd packages/api
go test ./...
go vet ./...If your local sandbox cannot write to the default Go cache, use a workspace-local cache:
cd packages/api
mkdir -p .cache/go-build .cache/go-mod
GOCACHE="$PWD/.cache/go-build" GOMODCACHE="$PWD/.cache/go-mod" go test ./...
GOCACHE="$PWD/.cache/go-build" GOMODCACHE="$PWD/.cache/go-mod" go vet ./...Run the API with Docker:
docker build -t uddi-api ./packages/api
docker run --rm -p 8080:8080 uddi-apiRun the current local compose stack:
pnpm docker:devVerify the Docker API and SDK together with the E2E smoke test:
pnpm e2e:smokeThe same smoke test is available as the manual E2E Smoke workflow in GitHub Actions and runs automatically for release tags.
With compose running, run the optional Postgres integration test:
pnpm api:test:postgresRun the optional Redis integration test:
pnpm api:test:redisIf you previously ran an older compose file and see orphan containers or Postgres role errors:
docker compose -f infra/docker/docker-compose.dev.yml down -v --remove-orphans
docker compose -f infra/docker/docker-compose.dev.yml up --buildIf Docker reports that uddi-api, uddi-postgres, or uddi-redis is already in use from an older compose file:
docker rm uddi-api uddi-postgres uddi-redisOn Docker Desktop, the API may briefly log DID database not ready; retrying after down and up while Docker DNS and Postgres are coming back. The API retries startup database connection automatically. If it still fails after all retries, recreate the stack with the down -v --remove-orphans command above.
Run the end-to-end authentication example:
pnpm build
pnpm example:auth-flowRun the npm package quickstart example:
pnpm --filter @uddi/example-npm-quickstart startInstall the published TypeScript packages:
pnpm add @uddi/core @uddi/sdkUser/holder side:
import { UddiClient } from '@uddi/sdk';
const client = new UddiClient({ network: 'local' });
const { did } = await client.createIdentity();
console.log(did);Verifier side:
import { UddiVerifier } from '@uddi/sdk';
const verifier = new UddiVerifier({
network: 'local',
serviceId: 'my-app',
apiKey: process.env.UDDI_API_KEY!,
});
const challenge = await verifier.createAuthChallenge();
const result = await verifier.verifyAuth(challenge.challengeId, presentation);
if (result.valid) {
console.log(`Authenticated DID: ${result.did}`);
}Detailed request and response examples live in docs/API.md. A machine-readable OpenAPI 3.1 contract is available at docs/openapi.yaml and is served by the API at GET /openapi.yaml. When the API is running, Swagger UI is available at GET /docs.
Deployment guidance for shared and production-like environments lives in docs/DEPLOYMENT.md.
Release notes are tracked in CHANGELOG.md.
Current REST surface:
GET /healthGET /readyGET /metricsPOST /v1/did/registerGET /v1/did/{did}POST /v1/did/revokePUT /v1/did/{did}/updateGET /v1/credentials/{did}- API key requiredPOST /v1/credentials/issue- API key requiredPOST /v1/credentials/revoke- API key requiredGET /v1/credentials/{id}/verify- API key requiredPOST /v1/verify/challenge- API key requiredPOST /v1/verify/auth- API key requiredPOST /v1/verify/claim- API key required, ZKP adapter verificationGET /v1/admin/api-keys/- admin token requiredPOST /v1/admin/api-keys/- admin token requiredPOST /v1/admin/api-keys/revoke- admin token requiredPOST /v1/proof/generate- ZKP adapter generationGET /v1/registry/stats
When UDDI_DATABASE_URL is configured, the API persists DID registry and API key data in Postgres. Without it, the API falls back to in-memory stores for lightweight tests and local experimentation.
+------------------------------------------------------------------+
| Applications |
| web apps, verifier services, wallets, backend systems |
+-------------------------------+----------------------------------+
|
| @uddi/sdk
| - UddiClient: holder/user flows
| - UddiVerifier: verifier/app flows
v
+------------------------------------------------------------------+
| Go API Gateway |
| |
| Public routes |
| - health |
| - DID register / resolve / revoke |
| - ZKP proof generation adapter |
| |
| Protected routes |
| - credential endpoints |
| - auth challenge / auth verification |
| - ZKP claim verification adapter |
| |
| Security checks |
| - API key + service ID validation |
| - Ed25519 auth presentation verification |
| - challenge replay protection |
| - service binding and timestamp windows |
+---------------+-----------------------+--------------------------+
| |
| |
v v
+----------------------------+ +----------------------------------+
| Postgres | | Redis |
| | | |
| DIDStore | | ChallengeStore |
| - dids | | - short-lived auth challenges |
| | | - single-use verification state |
| APIKeyStore | | - TTL based on challenge expiry |
| - api_keys | | |
+----------------------------+ +----------------------------------+
|
| future registry adapter
v
+------------------------------------------------------------------+
| Blockchain Registry (Roadmap) |
| planned Substrate node / DID registry / revocation |
+------------------------------------------------------------------+
+------------------------------------------------------------------+
| @uddi/core |
| identity generation, DID derivation, signing, DID documents, |
| Verifiable Credential issue/verify/hash/presentation primitives |
+------------------------------------------------------------------+
+------------------------------------------------------------------+
| ZKP Layer |
| Circom circuit drafts exist today for age and citizenship claims. |
| Runtime prover/verifier service integration is still roadmap. |
+------------------------------------------------------------------+
1. Holder creates identity
@uddi/sdk -> @uddi/core
- generate Ed25519 keypair
- derive did:uddi:z...
- private key stays with holder
2. Holder registers DID
UddiClient -> API /v1/did/register -> DIDStore
- API verifies ownership signature
- DID document metadata is stored in Postgres when configured
3. Verifier creates auth challenge
UddiVerifier -> API /v1/verify/challenge -> APIKeyStore + ChallengeStore
- API validates service ID + API key
- challenge is stored in Redis with TTL
4. Holder authenticates
UddiClient -> @uddi/core signing
- signs challengeId:nonce:did:timestamp
5. Verifier checks authentication
UddiVerifier -> API /v1/verify/auth
- API consumes challenge once
- validates service binding and timestamp window
- resolves DID public key
- verifies Ed25519 signature
6. Issuer registers credential
UddiClient / issuer app -> API /v1/credentials/issue -> CredentialStore
- API resolves issuer and subject DIDs
- verifies Ed25519 credential proof
- stores credential registry record
| Concern | Default/Test Mode | Compose Dev Mode |
|---|---|---|
| DID registry | Memory store | Postgres dids table |
| API keys | Memory seeded keys | Postgres api_keys table |
| Auth challenges | Memory store | Redis with TTL |
| API key management | Memory store | Postgres api_keys table |
| Credential registry | Memory store | Postgres credentials table |
| ZKP verification | Stub/circuit drafts | Roadmap service |
The Go API applies security headers, a maximum request body size, and a simple per-IP rate limiter. Configure these values with:
UDDI_MAX_REQUEST_BODY_BYTES=1048576
UDDI_RATE_LIMIT_REQUESTS=120
UDDI_RATE_LIMIT_WINDOW_SECONDS=60
The API exposes:
GET /health # liveness
GET /ready # readiness
GET /metrics # JSON counters and latency summary
HTTP requests are logged with method, path, status, duration, remote address, request ID, and user agent.
When UDDI_DATABASE_URL is configured, the API runs versioned Postgres migrations at startup. Applied versions are tracked in the schema_migrations table.
sequenceDiagram
autonumber
actor Holder as Holder App
participant SDK as @uddi/sdk UddiClient
participant Core as @uddi/core
participant API as Go API Gateway
participant DIDStore as DIDStore
participant DB as Postgres
Holder->>SDK: createIdentity()
SDK->>Core: generateIdentity()
Core-->>SDK: DID, public key, private key
SDK->>Core: sign "register:{did}:{timestamp}"
Core-->>SDK: signatureBase64
SDK->>API: POST /v1/did/register
API->>API: validate DID format
API->>API: verify Ed25519 ownership signature
API->>DIDStore: DIDExists(did)
DIDStore->>DB: SELECT EXISTS FROM dids
DB-->>DIDStore: false
API->>DIDStore: RegisterDID(did, publicKey)
DIDStore->>DB: INSERT INTO dids
DB-->>DIDStore: persisted
API-->>SDK: 201 REGISTERED + txHash
SDK-->>Holder: { did }
sequenceDiagram
autonumber
actor VerifierApp as Verifier App
actor Holder as Holder App
participant VerifierSDK as @uddi/sdk UddiVerifier
participant HolderSDK as @uddi/sdk UddiClient
participant Core as @uddi/core
participant API as Go API Gateway
participant APIKeys as APIKeyStore
participant Challenges as ChallengeStore
participant DIDStore as DIDStore
participant Redis as Redis
participant DB as Postgres
VerifierApp->>VerifierSDK: createAuthChallenge()
VerifierSDK->>API: POST /v1/verify/challenge
API->>APIKeys: Validate(serviceId, apiKey)
APIKeys->>DB: SELECT api_key_hash FROM api_keys
DB-->>APIKeys: active key hash
APIKeys-->>API: valid
API->>Challenges: Save(challenge)
Challenges->>Redis: SET challenge with TTL
Redis-->>Challenges: OK
API-->>VerifierSDK: challengeId, nonce, qrCode, expiresAt
VerifierSDK-->>VerifierApp: auth challenge
VerifierApp-->>Holder: present QR/deep link
Holder->>HolderSDK: authenticate(challenge)
HolderSDK->>Core: sign "challengeId:nonce:did:timestamp"
Core-->>HolderSDK: signature
HolderSDK-->>Holder: presentationBase64
Holder-->>VerifierApp: presentationBase64
VerifierApp->>VerifierSDK: verifyAuth(challengeId, presentation)
VerifierSDK->>API: POST /v1/verify/auth
API->>APIKeys: Validate(serviceId, apiKey)
APIKeys->>DB: SELECT api_key_hash FROM api_keys
DB-->>APIKeys: active key hash
APIKeys-->>API: valid
API->>Challenges: Get(challengeId)
Challenges->>Redis: GET challenge
Redis-->>Challenges: challenge payload
API->>Challenges: Delete(challengeId)
Challenges->>Redis: DEL challenge
API->>API: validate service binding and timestamp
API->>DIDStore: ResolveDID(did)
DIDStore->>DB: SELECT FROM dids
DB-->>DIDStore: DID document + public key
API->>API: verify Ed25519 presentation signature
API-->>VerifierSDK: valid, did, verifiedAt
VerifierSDK-->>VerifierApp: authentication result
sequenceDiagram
autonumber
actor VerifierApp as Verifier App
actor Holder as Holder App
participant HolderSDK as @uddi/sdk UddiClient
participant VerifierSDK as @uddi/sdk UddiVerifier
participant API as Go API Gateway
participant APIKeys as APIKeyStore
participant ZKP as ZKP Service Adapter
participant Circuits as Circom Circuits
Holder->>HolderSDK: generateProof({type, params})
HolderSDK->>API: POST /v1/proof/generate
API->>ZKP: Generate proof request
ZKP-->>API: development proof or remote proof
API-->>HolderSDK: ZkProof
HolderSDK-->>Holder: proof
Holder-->>VerifierApp: share proof
VerifierApp->>VerifierSDK: verifyClaim(did, claim, proof)
VerifierSDK->>API: POST /v1/verify/claim
API->>APIKeys: Validate(serviceId, apiKey)
APIKeys-->>API: valid
API->>ZKP: Verify proof
ZKP->>Circuits: validate proof shape locally or delegate remotely
Circuits-->>ZKP: verification result / roadmap circuit backend
ZKP-->>API: valid / invalid
API-->>VerifierSDK: ProofVerificationResult
VerifierSDK-->>VerifierApp: claim verification result
- Replace in-memory blockchain client with real registry integration.
- Add DID/VC compliance coverage.
- Build ZKP prover/verifier service around the existing circuits.
- Add compliance tests for DID and Verifiable Credentials.
- Add mobile wallet/holder application.
- Prepare testnet deployment.
Read CONTRIBUTING.md before opening issues or pull requests. This project is still alpha, so small, well-tested improvements to the core, SDK, API contracts, and documentation are especially useful.
UDDI is released under the Apache 2.0 License.