Skip to content

Federation

Federation moves CryptidEnvelope values between servers unchanged. A receiving server learns exactly what a local server learns: a routing string and an opaque blob.

It authenticates servers, never users. PrivacyPass tokens are server-local and MUST NOT cross this boundary - a token minted by one server is meaningless to another, and forwarding one would tie a user’s action to a specific remote request.

  • Input: RelayTransaction { origin_server, transaction_id, envelopes }
  • Output: RelayReceipt { accepted }
  • Auth: Origin signature
  • Idempotent: By transaction_id
  • Errors: ORIGIN_SIGNATURE_INVALID, TRANSACTION_MISMATCH, VERSION_UNSUPPORTED, FEATURE_UNSUPPORTED, ORIGIN_BLOCKED, CERT_FINGERPRINT_MISMATCH
  • Receiving servers MUST verify X-Origin-Signature against the peer’s server_signing_key from discovery, before queueing anything
  • Receiving servers MUST verify the TLS certificate against the peer’s certificate_fingerprint
  • origin_server MUST match the X-Origin-Server header
  • transaction_id MUST match the URL path
  • Receiving servers MUST treat a repeated transaction_id as idempotent
  • Receiving servers MUST NOT infer any user-level authorization from a valid server signature
  • An envelope MUST be delivered only to the exact address it names

Covers the canonical request defined in Wire Format

"cryptid-federation-v1" || method || path || origin_server || transaction_id || body

Each component length-prefixed, body the exact transmitted bytes. The leading domain separator stops a signature produced in one context verifying in another.

The payload’s timestamp is when the origin accepted the envelope. The receiving server assigns its own received_at on queueing and uses that for retention and ordering.

  • Receiving servers MUST assign received_at themselves
  • Receiving servers MUST NOT use the origin’s timestamp to compute expiry

A peer that could set expiry could keep an envelope alive indefinitely, or expire it on arrival. The origin’s timestamp is advisory.

PUT /federation/v1/deliver/{transaction_id}
X-Origin-Server: server1.com
X-Origin-Signature: <ed25519 over the canonical request>
Content-Type: application/json

Envelopes for different recipients SHOULD NOT share a transaction.

  • Server SHOULD dispatch envelopes for distinct recipients in separate transactions
  • Servers MAY batch retries of the same envelope
  • Servers SHOULD introduce jitter between transactions from a single fan-out
Never Crosses Why
PrivacyPass Tokens server-local; forwarding one would link a user action to a remote request
Mailbox ownership sessions scoped to one mailbox at one server
Any sender identity the outer layer is HPKE Base mode - no sender key participates at all
Device records announcement state never leaves its home server

There is no sender_address and no sender_signature. An ephemeral key is generated per envelope and discarded. Sender identity lives in the MLS credential, inside the MLS ciphertext, inside the HPKE-sealed blob - two decryptions below anything either server can reach.

A server MAY refuse a peer entirely, returning ORIGIN_BLOCKED.

  • Blocked origins MUST be refused before signature verification, to avoid spending work on them
  • Servers SHOULD aggregate abuse per origin rather than per envelope

Blocking a peer also blocks KeyPackage fetches routed through it and any Welcome bound for its users, so it ends group formation with that server, not just message delivery.