Skip to content

feat: DFOS credentials, delegation, revocation, and full cross-language parity#43

Merged
bvalosek merged 24 commits intomainfrom
protocol-oss-build
Apr 15, 2026
Merged

feat: DFOS credentials, delegation, revocation, and full cross-language parity#43
bvalosek merged 24 commits intomainfrom
protocol-oss-build

Conversation

@bvalosek
Copy link
Copy Markdown
Member

@bvalosek bvalosek commented Apr 14, 2026

Summary

Complete credential and authorization layer for the DFOS protocol, with full parity across TypeScript and Go implementations:

  • DFOS Credentials — UCAN-style JWS authorization tokens with CID-addressable payloads, delegation chains via prf arrays, and monotonic attenuation enforcement (max 16 hops)
  • Revocation system — CID-targeted credential revocation with cascading invalidation through delegation chains, both at ingestion and access-check time. Revocation is forward-looking — committed content operations are not retroactively invalidated
  • Standing authorization — Public credentials (aud: "*") stored by relays, granting any authenticated identity access without per-request credential headers
  • chain:* wildcard resource — Broadest scope credential covering all content chains, with full attenuation hierarchy: chain:* > manifest:M > chain:X
  • Delegation chain verification — Recursive prf walk with signature verification, audience linkage, expiry bounds, revocation at every hop, and identity deletion checks
  • Historical key resolution — Credentials use historical key resolution (walking the full identity chain log), surviving key rotation at both ingestion and access-check time. Auth tokens use current-state-only resolution. Shared createHistoricalIdentityResolver helper eliminates duplication
  • Clean credential API — Go CreateCredential uses att-based vocabulary (resource, action) directly. No legacy credType shim. VerifiedCredential carries full Att []AttEntry array
  • Idempotency guards — All ingestion functions (identity, content, beacon, countersign, revocation, credential) consistently check for duplicate-but-different JWS tokens
  • Documents endpointGET /content/:contentId/documents returns document history with operation CIDs, document CIDs, signer DIDs, and timestamps
  • Manifest transitive authorizationmanifest:<id> credentials transitively cover all content chains indexed by that manifest's entries
  • Go protocol library exportsAttEntry, ParseAtt, ParsePrf, ParseResource, ParseActions, IsAttenuated, VerifyRevocation extracted to protocol library
  • SQLite store — Full implementations for revocations, public credentials, and documents tables with proper indexes
  • Protocol site — New /credentials and /siwd spec pages, updated navigation across all pages

Test coverage

  • 242 TS protocol tests + 107 TS relay tests passing
  • Go protocol: 22 delegation/attenuation unit tests + existing tests passing
  • Go conformance: 113 tests (11 credential security tests) passing against both TS and Go relay implementations
  • Tests cover: multi-hop delegation chains, chain:* wildcard access, attenuation violation rejection, cascading revocation, audience mismatch, delegation expiry bounds, delegation gap, root mismatch, credential ingestion/access after key rotation

Specs

  • CREDENTIALS.md — Full credential spec including chain:* wildcard, attenuation rules, delegation chain verification, revocation scope semantics, key resolution (historical vs current-state)
  • SIWD.md — Sign In With DFOS specification for third-party identity verification
  • PROTOCOL.md — Updated with credential references and terminology alignment
  • WEB-RELAY.md — Updated with credential endpoints and revocation semantics
  • CONTENT-MODEL.md — Updated content model terminology

Test plan

  • pnpm typecheck — 0 errors
  • pnpm test — all TS tests pass (107 relay, 242 protocol)
  • Go protocol unit tests — all pass (including 22 delegation tests)
  • Go conformance tests against TS relay: 113 pass
  • Go conformance tests against Go relay: 113 pass
  • Protocol site builds with new credentials and SIWD pages
  • Verify protocol site renders correctly in browser
  • Container-based conformance test run

Generated with Claude Code

bvalosek and others added 11 commits April 14, 2026 11:03
…-based auth

Replace VC-JWT credential system with DFOS credentials — UCAN-style
delegation chains with CID-addressable payloads, monotonic attenuation,
and two resource types (chain: exact, manifest: transitive). Delete
credential.ts entirely, no backward compat (pre-v1).

Steps implemented:
- Step 1: DFOS Credentials (create, verify, delegation chains, attenuation,
  resource matching with manifestLookup callback, public aud:"*" semantics)
- Step 2: Content chain authorization updated to use DFOS credentials with
  resolveIdentity for delegation chain verification
- Step 3: Beacon update — manifestContentId replaces merkleRoot, drop version
  field. Beacon is now a manifest pointer, not a merkle root announcement.
- Step 4: Revocation artifacts — new signed revocation type, gossiped like
  beacons, permanent (no un-revoke)

Relay updates:
- Content-plane auth uses verifyDFOSCredential + verifyDelegationChain
- Ingestion pipeline passes resolveIdentity for credential verification
- Beacon response shape updated for new VerifiedBeacon type

235 protocol tests + 91 relay tests = 326 total, all passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…(Step 5)

Extend RelayStore interface with revocation set and public credential
storage. MemoryRelayStore implements both with Map-backed data
structures.

Ingestion pipeline classifies and processes two new artifact types:
- did:dfos:revocation → verify, add to revocation set, remove any
  stored public credential that was revoked
- did:dfos:credential (aud: "*") → verify signature, check not revoked,
  store as standing authorization. Private credentials (aud: specific
  DID) are silently ignored.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add verifyContentAccess to auth module — checks creator access, stored
public credentials, and per-request credentials in order. Replaces the
old verifyReadCredential that did inline VC-JWT verification.

Well-known endpoint now returns structured capabilities object:
{ proof, content, documents, log } instead of flat boolean fields.
Version bumped to 0.8.0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Paginated plaintext content reading endpoint. Returns resolved documents
for each operation in the content chain, ordered by chain sequence.

- StoredDocument type with operationCID, documentCID, document, signerDID, createdAt
- getDocuments on RelayStore — walks chain log, resolves blobs, paginates
- Auth-gated via verifyContentAccess (creator, public credential, or per-request credential)
- Cursor-based pagination using operation CID

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add reference-content-stream/v1 — a toy discriminated-union event schema
for developing and testing content stream patterns. Five actions:
create-item, update-item, delete-item, react, unreact.

Includes worked example with 6-operation chain demonstrating full CRUD
lifecycle, reactions, and deletion cascades, plus expected projected
state after folding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New spec documents:
- CREDENTIALS.md — DFOS credential format, delegation chains, attenuation
  rules, resource types, public credentials, revocation
- SIWD.md — Sign In With DFOS protocol, managed + sovereign signing,
  challenge schema, 3P verification

Updated specs:
- PROTOCOL.md — remove VC-JWT references, add credential/revocation
  pointers, update beacon payload (manifestContentId)
- WEB-RELAY.md — documents endpoint, credential-based auth, public
  credential ingestion, capabilities object, version 0.8.0
- CONTENT-MODEL.md — reference content stream schema, projection rules,
  createdByDID convention, targetOperationCID pattern

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…t, POSTER.html removal

Security: scope revocation storage to (issuerDID, credentialCID) so only
the credential issuer can revoke it. Previously any DID could submit a
revocation for any credential CID.

Schema consistency: add version: 1 to DFOSCredentialPayload and
RevocationPayload, matching the convention of all other payload schemas.
Add .min(1) to credential iss field. Fix audience check to reject when
requesterDID is absent on non-public credentials.

Spec alignment: remove all dangling VC-JWT references across PROTOCOL.md,
WEB-RELAY.md, SIWD.md, CREDENTIALS.md, CLAUDE-SKILL.md, README.md.
Fix well-known capabilities to match implementation. Fix credential type
references (DFOSContentRead/Write → generic DFOS credentials with
action attenuations). Update reference implementation map.

OpenAPI: update well-known response to capabilities object, fix beacon
schema (manifestContentId, flat response), add documents endpoint,
fix credential header descriptions.

Cleanup: remove POSTER.html (stale, superseded by protocol site).
Regenerate example fixtures.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update dfos-protocol-go to match the new DFOS credential format
(replacing VC-JWTs) and new beacon format (manifestContentId replacing
merkleRoot). Update relay-conformance tests for the same changes.
Run prettier across TS files.

Go changes:
- SignBeacon: manifestContentId replaces merkleRoot, drop version
- CreateCredential: DFOS credential format with CID derivation
- VerifyCredential: parse flat DFOS credential payload instead of
  nested vc+jwt structure
- VerifyBeacon: manifestContentId (22-char content ID) replaces
  merkleRoot (64-char hex), drop version check
- All Go tests updated and passing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- dfos-web-relay-go: well-known response uses capabilities object,
  beacon GET returns flat fields (manifestContentId, createdAt),
  BeaconPayload uses manifestContentId
- relay-conformance: TestWellKnown checks capabilities.proof,
  TestBeaconReplacement uses manifestContentId
- Run prettier across all TS/MD files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ce tests

- dfos-cli: beacon announce takes manifestContentId instead of
  building merkle root from content IDs. Show command reads flat
  beacon response format.
- site-protocol: remove poster.astro page (POSTER.html was deleted)
- relay-conformance: remaining beacon tests use manifestContentId
  instead of BuildMerkleRoot
- dfos-web-relay-go: beacon GET returns flat fields, well-known
  uses capabilities object
- Run prettier across all files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…t scopes, terminology cleanup

- TS: delegation chain revocation checking at every prf level
- TS: manifest scope resolution with manifestLookup callback in verifyContentAccess
- TS: getPublicCredentials returns manifest-scoped credentials for chain requests
- Go protocol: CID integrity check, version validation, VerifiedCredential struct cleanup (Aud/Action/CID fields)
- Go relay: revocation + credential ingestion, store, and classification
- Go relay: documents endpoint (GET /content/:contentId/documents)
- Go relay: well-known documents capability, version 0.8.0
- Go relay: updated verifyReadCredential error messages
- OpenAPI: enum updates (IngestionResult.kind, StoredOperation.chainType), field fixes (nextCursor, headCID, limit defaults), added log endpoints, uploadBlob path fix
- Prose: PROTOCOL.md, CREDENTIALS.md, WEB-RELAY.md terminology (VC-JWT → DFOS credential, sub → aud)
- CLI: help text terminology cleanup
- Example fixtures: sub → aud, subjectPublicKey → audiencePublicKey
- Go test comments: VC → credential terminology

Co-Authored-By: Claude <noreply@anthropic.com>
@bvalosek bvalosek changed the title feat: DFOS credentials, beacon manifests, revocations, documents endpoint feat: DFOS credentials, manifest beacons, revocations, and full cross-language parity Apr 14, 2026
bvalosek and others added 6 commits April 14, 2026 13:59
Co-Authored-By: Claude <noreply@anthropic.com>
- Rewrite Go relay auth with full verifyContentAccess matching TS relay:
  creator check → public credentials → per-request credential, with
  delegation chain verification, revocation at every level, manifest
  transitive lookup, and monotonic attenuation enforcement
- Fix Go GetPublicCredentials manifest matching bug (dead code)
- Fix Go ingestRevocation: unconditional CID check, version/type validation
- Restore beacon version: 1 field across TS/Go schemas for consistency
- Add TS relay integration tests: revocation ingestion, public credential
  ingestion, standing authorization, revocation cascade, documents endpoint
- Fix stale test names (DFOSContentRead → read credential)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…elegation chain parity, SQLite store

- F1: TS relay credential verification now uses historical key resolution
  (credentials survive key rotation, revocation is the invalidation mechanism)
- F2: chain:* wildcard resource support in matchesResource and isAttenuated
  across TS protocol, TS relay, Go relay, and Go protocol library
- F3: Go verifyCredentialCore att pairing fix (action+resource from same entry)
- F4: Go protocol-level delegation chain walk (VerifyDelegationChain) —
  content chain authorization now walks prf recursively instead of flat
  iss != creatorDID check
- F5: Go VerifyRevocation extracted to protocol library, relay uses it
- F6: SQLite store implementations for all 7 new methods (revocations,
  public credentials, documents) with schema DDL
- F7: Go conformance tests for revocation, public credentials, standing
  authorization, and documents endpoint
- F8: TS tests for chain:* wildcard attenuation, cascading revocation,
  and wildcard standing authorization

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ization

- Make verifyDelegationChain unexported (only called internally)
- Add chain:* wildcard handling in verifyContentAuthorization so
  wildcard-scoped write credentials work for delegated content creation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Document chain:* wildcard resource pattern in CREDENTIALS.md with full
  attenuation hierarchy table (chain:* > manifest:M > chain:X)
- Export AttEntry, ParseAtt, ParsePrf, ParseResource, ParseActions,
  IsAttenuated from Go protocol library — relay imports shared types
  instead of maintaining ~200 lines of duplicated logic
- Fix conformance test timestamp format (RFC3339 → protocol millisecond
  format) so revocation tests pass against both TS and Go relays
- Add conformance-server.ts for running Go conformance tests against
  the TS relay locally

Conformance: 102 tests pass against both TS relay and Go relay.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PROTOCOL.md links to /credentials and SIWD.md exists but neither had
site pages. Adds both spec pages following the existing pattern and
updates footer navigation + specs grid on all pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bvalosek bvalosek changed the title feat: DFOS credentials, manifest beacons, revocations, and full cross-language parity feat: DFOS credentials, delegation, revocation, and full cross-language parity Apr 15, 2026
bvalosek and others added 7 commits April 14, 2026 19:36
…ecurity

Add 22 unit tests for delegation.go exports (ParseResource, ParseActions,
ParseAtt, ParsePrf, IsAttenuated) covering chain:* wildcard, manifest
interactions, narrowing/widening, and edge cases.

Add 9 conformance tests exercising credential security boundaries:
- chain:* wildcard standing auth and per-request credentials
- audience mismatch rejection
- cascading revocation (parent revoked blocks child)
- delegation expiry bounds enforcement
- attenuation violation rejection (scope widening)
- delegation gap rejection (child issuer not in parent audience)
- multi-hop delegation chain (3 levels: creator → A → B → reader)
- delegation root mismatch rejection

All tests verified against both TS relay and Go relay.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Credentials are long-lived artifacts — their validity persists across key
rotations. Revocation (not key rotation) is the invalidation mechanism.

Previously, ingest.ts used current-state-only key resolution for public
credential ingestion, causing valid credentials signed before a key
rotation to be rejected. Now uses historical key resolution (walking the
full identity chain log) consistent with access-time verification.

Go relay already used historical resolution — no code change needed.

Updates CREDENTIALS.md spec prose to document the key resolution
distinction between auth tokens (current-state) and credentials
(historical). Adds key rotation row to the comparison table.

Adds tests:
- TS relay: credential ingestion after key rotation, per-request
  credential access after key rotation (2 new tests, 107 total)
- Go conformance: public credential ingestion after key rotation,
  per-request credential after key rotation (2 new tests, verified
  against both TS and Go relays)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…y gaps

- Extract createHistoricalIdentityResolver as shared helper (was duplicated
  in auth.ts and ingest.ts)
- Fix content chain authorization to use historical key resolution (parity
  with Go relay)
- Add idempotency guards to ingestRevocation and ingestPublicCredential
- Update Go VerifiedCredential to carry full Att []AttEntry array
- Replace legacy CreateCredential(credType, contentID) API with
  CreateCredential(resource, action) — new att-based vocabulary
- Update all conformance tests, protocol tests, and CLI to new API
- Add revocation scope prose to CREDENTIALS.md (forward-looking only)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename VerifyCredential expectedType parameter to expectedAction,
accepting "read"/"write" directly instead of mapping through legacy
type strings. Update all call sites across protocol library, CLI,
and tests. No legacy credential type vocabulary remains in active code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The well-known endpoint now reads the version from package.json at
runtime via createRequire, eliminating a manual sync point during
releases. QUICKSTART.md updated to reference :latest tag with a note
about pinned versions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bvalosek bvalosek merged commit a25c51d into main Apr 15, 2026
9 checks passed
@bvalosek bvalosek deleted the protocol-oss-build branch April 15, 2026 10:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant