Monaco Protocol SDK v1.0.55
This release covers the consumer-facing changes since v1.0.54. Nothing in it changes a request or response field, and nothing changes for a client that upgrades and does nothing else. REST session authentication now accepts a second, opt-in signing protocol — RFC 9421 HTTP message signatures over the same Ed25519 session keys — alongside the legacyX-Monaco-* headers, which remain supported with no retirement date. The TypeScript and Rust SDKs can produce the new signatures, but both default to legacy, so opting in is a deliberate per-application step and one you should only take against a gateway that already verifies it. Alongside that, the OpenAPI specification now declares an authentication requirement on 24 endpoints that previously declared none — a specification correction, not a change in what the gateway enforces.
Added
Opt-in RFC 9421 request signing
REST session authentication accepts RFC 9421 HTTP message signatures as an alternative to the legacyX-Monaco-PublicKey / X-Monaco-Timestamp / X-Monaco-Signature headers. Both protocols use the same wallet-authorized Ed25519 session keys and run the same session expiry, revocation, delegated-agent permission, and account-restriction checks. WebSocket and gRPC signing are unchanged.
A signed request carries three headers:
monaco and exactly one dictionary member is accepted; the four covered components appear in the order shown; created, keyid, and alg are required; and extra components, extra labels, extra parameters, or another digest algorithm are rejected. created is an integer Unix timestamp in seconds within 30 seconds of server time — legacy timestamps are milliseconds. keyid is the registered session public key as 64 lowercase hexadecimal characters. @query begins with ?, keeps raw ordering, duplicates and percent encoding, and is ? when the query is absent. Content-Digest is RFC 9530 SHA-256 over the exact body bytes, including the empty body on a GET.
Presence of Signature or Signature-Input selects RFC verification, and failure never falls back to legacy: there is no automatic protocol downgrade. Sending Signature or Signature-Input alongside any X-Monaco-* header is rejected as 401 Unauthorized. Content-Digest on its own is ordinary HTTP integrity metadata — it neither selects RFC verification nor overrides the body hash legacy verification computes independently.
The 30-second window bounds how long a captured signature stays usable; it does not stop an identical signed request from being accepted again inside that window, and Monaco keeps no nonce or replay cache. Use the endpoint’s idempotency mechanism for exactly-once behavior, and when re-signing an aged-out retry, keep the original idempotencyKey and payload. See HTTP message signatures for the full profile, signature base, and migration sequence.
SDKConfig.requestSigning selects the protocol in TypeScript
createMonacoSDK (and new MonacoSDK) accepts requestSigning: "legacy" | "rfc9421", defaulting to "legacy". The RequestSigning type is exported from @0xmonaco/types.
rfc9421 mode the SDK signs the final URL path and query plus the serialized body, requires the body to be a string, sets redirect: "error" on authenticated requests so a signed request is never forwarded unchanged, and throws if the caller supplies any signature header itself. Public and backend-key requests keep their existing authentication either way. See TypeScript migration.
Client::new_authenticated in the Rust REST SDK
The Rust REST SDK gains a signing client constructor:
wasm32. Existing unsigned constructors are unchanged. RequestSigning::Legacy selects the legacy headers for a gateway that has not migrated, and the lower-level SessionSigner::sign_at helper signs a reusable reqwest request, with the caller responsible for preserving the signed bytes and disabling redirects. Streaming bodies are rejected rather than signed as empty. See Rust migration and Sign Authenticated Requests.
Fixed
The specification declares authentication on 24 previously undeclared endpoints
The OpenAPI specification gains amonacoHttpSignature security scheme next to the existing monacoSignature, and every session-authenticated operation now lists both. While making that change, 24 operations were found to declare no security requirement at all, so the generated API reference and any client generated from the specification presented them as public:
- seven endpoints under
/api/v1/positions—GET /api/v1/positions,GET /api/v1/positions/history,GET /api/v1/positions/{positionId},GET /api/v1/positions/{positionId}/risk,POST /api/v1/positions/batch-close-all,POST /api/v1/positions/{positionId}/close, andPOST /api/v1/positions/{positionId}/tp-sl.GET /api/v1/positions/{positionId}/pnl/historyalready declared its requirement and is unaffected - all fourteen endpoints under
/api/v1/margin— the margin account and parent margin account reads and their movements,GET /api/v1/margin/collateral/available, the collateral transfer-in and transfer-out endpoints, and the threesimulate-order-riskendpoints - the three conditional order endpoints,
GET /api/v1/orders/conditional,GET /api/v1/orders/conditional/{conditionalOrderId}, andDELETE /api/v1/orders/conditional/{conditionalOrderId}
Request-body buffering is scoped to session-authenticated routes
The gateway buffered and hashed every request body globally so that signature verification could cover it. That buffer is now mounted only on session-authenticated resources. Signed routes still read and hash their bodies under the same 2 MiB bound; public and backend-key routes use their normal extractor limits instead. No request or response shape changes, and body hashing is not removed from any signed route.Upgrade
requestSigning defaults to "legacy" and the Rust SDK’s existing constructors are untouched. Before selecting rfc9421, confirm the gateway you target verifies it, because there is no automatic downgrade — a client that opts in early fails closed. Never mix the two credential sets on one request. If you sign requests with your own client rather than an SDK, read the profile end to end before implementing it: the covered-component list, their order, the seconds-based created, and the exact digest encoding are all verified strictly. If you generate a client from the OpenAPI specification, regenerate it so the 24 corrected endpoints are signed, and audit any client generated before v1.0.55 to confirm it was not calling them unsigned.
