Skip to main content
Every POST /mcp must be signed. Unsigned, expired, replayed, or wrongly keyed requests never reach a tool. GET /.well-known/fau-node is not signed.

Covered components

Always cover:
  • @method
  • @target-uri (full public URL, including scheme — e.g. https://n….relay.fau.run/mcp)
  • @authority (hostname only)
  • content-digest

Signature parameters

Default lifetime in the reference signer is 120 s (still ≤ 300).

Content-Digest

SHA-256 of the raw body bytes, RFC 9530 form with standard Base64 (not base64url):

Example headers

Label is sig1 in the reference implementation:
Signature / digest use standard Base64 with surrounding colons. Key documents and queue envelopes use base64url.

Pseudocode

Normative edge cases live next to the verifier in node/src/fedagent/crypto/signatures.py (sign_request).

Rules that bite

  • Agent domain must contain at least one dot (e.g. assistant.example), and must not equal the node hostname.
  • Sign the public URL you will send on the wire. Redirects break signatures — call /mcp (or /mcp/) directly; do not follow 3xx.
  • Body larger than 256 KiB → HTTP 413 {"error":"payload_too_large"}.
  • Missing/bad signature → HTTP 401 {"error":"signature_invalid",…} (not JSON-RPC).

Capability token (optional)

Tokens are optional. After phone approval the node usually remembers a grant by domain; retry the signed tool call without a Bearer header. If you do send a token, it must be bound to your domain and key fingerprint; an invalid token is typically ignored, not a hard 401.