Preview release.These docs are a work in progress. Pages are still being written, links may break, and structure may shift without notice. Treat everything here as a draft and report issues onGitHub.
This guide shows the minimum static-peer setup for delegated evaluation. It covers static peer configuration, inbound request verification, and the documented limits of the current implementation: no outbound Notary connector, no dynamic trust registration, and in-memory replay suitable for single-process pilots only.
What this enables
Section titled “What this enables”One trusted Notary can call another trusted Notary:
Agency B -> signed request JWT -> Agency A /federation/v1/evaluationsAgency B <- signed response JWT <- Agency AThe serving Notary verifies the request, enforces local peer policy, reads its own source only after policy passes, emits audit, and returns a signed result.
sequenceDiagram participant B as Agency B (requesting Notary) participant A as Agency A (serving Notary) participant Src as Source registry participant Audit as Audit sink B->>A: POST /federation/v1/evaluations (signed request JWT) A->>A: Verify signature, audience, time window, profile, purpose, replay, denylist, body limit A->>Src: Source read, only after policy passes Src-->>A: Source facts A->>Audit: Chained audit record A-->>B: Signed response JWT, or signed error, or Problem Details denial
The delegated evaluation exchange. Every check runs before any source read, and an audit write failure prevents a successful signed response.
Required environment
Section titled “Required environment”Set these before starting the serving Notary:
export REGISTRY_NOTARY_AUDIT_HASH_SECRET='change-me-audit-hash-secret'export REGISTRY_NOTARY_FEDERATION_RESPONSE_JWK='{"kty":"OKP","crv":"Ed25519","d":"...","x":"...","alg":"EdDSA"}'export REGISTRY_NOTARY_PAIRWISE_SUBJECT_HASH_SECRET='change-me-pairwise-secret'export EVIDENCE_SOURCE_TOKEN='source-token-issued-by-the-registry'Do not reuse the pairwise subject hash secret for audit hashing, cookies,
source tokens, credential signing, or federation response signing. Federation
response signing references a named key from evidence.signing_keys, so the
same local JWK and PKCS#11 providers are used for evidence and federation
signatures.
Minimal config shape
Section titled “Minimal config shape”evidence: signing_keys: federation-response: provider: local_jwk_env alg: EdDSA kid: agency-a-fed-1 status: active private_jwk_env: REGISTRY_NOTARY_FEDERATION_RESPONSE_JWK
federation: enabled: true node_id: did:web:agency-a.example.gov issuer: https://agency-a.example.gov jwks_uri: https://agency-a.example.gov/federation/jwks.json federation_api: https://agency-a.example.gov/federation/v1 supported_protocol_versions: - registry-notary-federation/v0.1 inbound_body_limit_bytes: 16384 max_request_lifetime_seconds: 300 clock_leeway_seconds: 60 signing: signing_key: federation-response pairwise_subject_hash: secret_env: REGISTRY_NOTARY_PAIRWISE_SUBJECT_HASH_SECRET response_shaping: minimum_denial_latency_ms: 250 emergency_denylist: node_ids: [] kids: [] peers: - node_id: did:web:agency-b.example.gov issuer: https://agency-b.example.gov jwks_uri: https://agency-b.example.gov/.well-known/jwks.json # Local Compose demos may use allow_insecure_private_network: true with # an HTTP service URL. Production peer JWKS URLs must use HTTPS. allowed_protocol_versions: - registry-notary-federation/v0.1 allowed_purposes: - https://purpose.example.gov/social-protection/service-delivery allowed_profiles: - disability_status_predicate source_scopes: - disability_registry:evidence_verification evaluation_profiles: - id: disability_status_predicate ruleset: disability-status-v1 claim_id: disability_status subject_id_type: national_id max_source_observed_age_seconds: 3600The local peers block is authoritative. Manifest metadata helps partners
configure each other, but it does not grant access.
allow_insecure_private_network is a development and lab escape hatch for
private Compose networks. It allows HTTP peer JWKS fetches through the shared
bounded-fetch policy while still blocking cloud metadata targets. Do not enable
it for production federation.
Request requirements
Section titled “Request requirements”Send POST /federation/v1/evaluations with:
Content-Type: application/jwt- compact JWS serialization
- protected header
typ = registry-notary-request+jwt alg = EdDSAkidpresent in the configured peer JWKS- payload claims
iss,sub,aud,iat,nbf,exp,jti,protocol,action,profile,purpose, andrequest
The serving Notary rejects the request before source reads when signature, audience, time window, profile, purpose, replay, emergency denylist, or body limit checks fail.
Response requirements
Section titled “Response requirements”Successful responses are compact signed JWTs with:
- protected header
typ = registry-notary-response+jwt issandsubfor the serving Notaryaudfor the requesting peer node idrequest_jticopied from the requestresult.subject_ref.hashas a pairwisehmac-sha256:handle
Stale source observations return HTTP 200 with a signed top-level error
object. Transport denials use RFC 9457 Problem Details JSON and do not prove whether the
subject exists.
Replay store
Section titled “Replay store”Replay protection is selected by the top-level replay block. The default
in_memory store is acceptable for local development, single-process pilots,
and tests:
replay: storage: in_memoryDo not run active-active federation with this store. Multiple serving Notary instances need a shared replay store before privileged federation traffic is enabled. For the full Redis replay configuration block, see the Replay Store section of the configuration reference.
federation.replay.storage is retained only for legacy configuration shape. If
it is set to redis, startup validation requires top-level
replay.storage = redis so the configured backend is unambiguous.
Verification checklist
Section titled “Verification checklist”Also confirm:
- federation routes are absent when
federation.enabledis false; - the peer JWKS contains the request signing
kid; - source tokens and raw subject identifiers do not appear in audit JSONL;
- audit write failure prevents a successful signed response;
- replaying the same request
jtireturns a denial.