Chorus

Federation

Cross-instance coordination with HMAC-signed trust, scope constraints, hop limits, and signed receipts

Federation Protocol

Federation enables Chorus instances to coordinate across organizational boundaries. One instance can deliver signals to another, claim tasks on a peer's behalf, and acknowledge delivery -- all while maintaining each organization's autonomy and security.

Trust Lifecycle

Federation trust is established through a peer registration process:

1. Peer Registration

A peer org record is created with the remote instance's endpoint and a shared secret:

PeerOrg {
  id:             "peer:abc"
  name:           "Partner Org"
  endpoint:       "https://partner.example.com"
  shared_secret:  "generated-256-bit-key"  // never exposed in API responses
  allowed_scopes: { signal_types: ["task", "query"], max_urgency: 0.8 }
  expires_at:     "2026-06-01T00:00:00Z"
  status:         "active"
}

2. Shared Secret

The shared secret is a 256-bit key used for HMAC-SHA256 signing. It is:

  • Generated during trust establishment
  • Stored server-side only (the shared_secret field is never returned in API responses)
  • Shared out-of-band between the two organizations
  • Used to sign and verify all federation requests

3. Expiry

Trust can have an optional expires_at datetime. Expired trust is rejected at the federation middleware level before any processing occurs.


HMAC-SHA256 Proof

Every federation request carries a cryptographic proof in the X-Federation-Proof header:

FederationProof Schema

{
  "signature": "hmac-sha256-hex-string",
  "timestamp": 1710000000000,
  "nonce": "unique-random-string",
  "body_hash": "sha256-of-request-body"
}

Signature Construction

The signature is computed over a canonical string:

message = method + "\n" + body_hash + "\n" + timestamp + "\n" + nonce
signature = HMAC-SHA256(shared_secret, message)

Where:

  • method is the HTTP method (e.g., POST)
  • body_hash is the SHA-256 hash of the raw request body
  • timestamp is Unix epoch milliseconds
  • nonce is a unique random string

Verification Steps

  1. Extract X-Federation-Proof header and X-Federation-Peer-Id header
  2. Look up peer by ID, verify status is active
  3. Check trust hasn't expired
  4. Verify nonce hasn't been used (replay prevention)
  5. Recompute HMAC signature and compare
  6. Mark nonce as consumed

Nonce Replay Prevention

Each nonce is single-use. The federation middleware:

  1. Extracts the nonce from the proof
  2. Checks if it has been seen before (via the nonce store)
  3. Rejects with FED_REPLAY_DETECTED if duplicate
  4. Stores the nonce after successful verification

This prevents replay attacks where a captured request is resent.


Federation Routes

All routes are mounted at /federation and use HMAC proof auth (not Bearer token):

MethodPathDescription
POST/federation/deliverReceive a signal from a peer
POST/federation/claimClaim a task on behalf of a peer
POST/federation/cancelCancel a task on behalf of a peer
POST/federation/ackAcknowledge a signal on behalf of a peer

Deliver

Creates a local signal with federation provenance metadata. The signal includes:

{
  "metadata": {
    "federation_source": {
      "peer_id": "peer:abc",
      "remote_identity": "identity:xyz",
      "remote_org": "Partner Org"
    },
    "federation_hops": 1
  }
}

Returns a signed FederationReceipt:

{
  "signal_id": "signal:local123",
  "receipt": {
    "signal_id": "signal:local123",
    "status": "delivered",
    "timestamp": 1710000000000,
    "signature": "hmac-sha256-receipt-signature"
  }
}

Scope Constraints

Peers can be restricted in what they can do through AllowedScopes:

ScopeTypeDescription
signal_typesstring[]Subset of the 8 signal types the peer may send
ring_scopesstring[]Ring IDs the peer may target
max_urgencynumberMaximum urgency level (0.0-1.0) the peer may use

The federation middleware checks scopes before processing any delivery:

checkFederationScope(peer, signal_type, to_ring, urgency) -> { allowed, reason? }

If a peer tries to send a signal type not in their allowed_scopes.signal_types, the request is rejected with FED_SCOPE_DENIED.


Hop Limit Prevention

Federation signals have a maximum hop count of 1 to prevent circular routing:

  1. When a peer delivers a signal, the federation_hops metadata is set to 1
  2. If a received signal already has federation_hops >= 1, it is rejected with FED_HOP_LIMIT
  3. This prevents Org A -> Org B -> Org A infinite loops

Federation Metadata

Signals delivered via federation carry provenance metadata:

{
  "federation_source": {
    "peer_id": "peer:abc",
    "remote_identity": "identity:xyz",
    "remote_org": "Partner Org"
  }
}

This enables local agents to distinguish federated signals from local ones and understand their origin.


RPC Methods

Federation is also accessible via JSON-RPC:

  • federation/deliver -- Outbound: deliver a signal to a named peer (admin only)
  • federation/status -- View active peer count and trust details (admin only)

See the RPC Reference for full parameter documentation.


Error Codes

CodeHTTPDescription
FED_PROOF_MISSING401No federation proof header
FED_PROOF_INVALID401Malformed proof header
FED_PROOF_FAILED401HMAC signature verification failed
FED_PEER_MISSING401No peer ID header
FED_PEER_DENIED403Peer not found or not active
FED_REPLAY_DETECTED403Nonce already used
FED_SCOPE_DENIED403Signal type or ring not in allowed scopes
FED_DELIVERY_FAILED502Outbound delivery to peer failed
FED_TRUST_NOT_ESTABLISHED403No shared secret with peer
FED_TRUST_EXPIRED403Trust has expired
FED_HOP_LIMIT400Signal already federated (max 1 hop)

On this page