A JSON Meta Application Protocol (JMAP) Subprotocol for WebSocket
Extracted elements (25)
Authenticating only the WebSocket handshake and reusing credentials for the connection lifetime eliminates the per-request authentication overhead present in the HTTP binding for JMAP, improving performance when authentication is expensive.
The optional client-specified "id" field on JMAP WebSocket requests exists because the server is permitted to process requests out of order, requiring an explicit correlation mechanism between requests and responses.
The "pushState" token encodes the entire server state visible to the user, allowing a client to immediately retrieve all changes that occurred while disconnected rather than issuing a series of "/changes" requests upon reconnection.
WebSocket JMAP optionally supports per-message compression (RFC 7692). HTTP request compression has very low deployment and is not viable for JMAP over HTTP, making WebSocket a better substrate for compressed requests.
Binary data (blobs) is not handled via the WebSocket JMAP subprotocol; it is handled per RFC 8620 Section 6 via a separate HTTP connection or stream, or via a future extension.
The WebSocket JMAP subprotocol is negotiated via HTTP/1.1 Upgrade (RFC 6455 Section 4) or HTTP/2 Extended CONNECT (RFC 8441 Section 5), and is intended to run over future HTTP bindings (e.g., HTTP/3) when a WebSocket handshake mechanism is defined for them.
A server MUST return an appropriate JSON Problem Details object for any request-level errors, such as an invalid JMAP object, an unsupported capability or method call, or exceeding a server request limit.
Authentication credentials used during the WebSocket handshake HTTP request remain in effect for the duration of the WebSocket connection. If credentials expire, the server MAY send a Close frame with status code 1008 (Policy Violation).
Before the WebSocket handshake, the client MUST perform a TLS handshake on the wss:// endpoint. If the TLS handshake fails, the client MUST close the connection.
Data frame messages in the JMAP subprotocol MUST be text frames containing UTF-8 encoded data. Fragmented WebSocket messages (split over multiple text frames) MUST be coalesced prior to parsing them as JSON objects.
Once the WebSocket connection is established, only JMAP API request, response, push notification, and error message types MUST NOT be transmitted over this connection; other message types are prohibited.
Servers supporting this specification MUST add a property named "urn:ietf:params:jmap:websocket" to the JMAP capabilities object, containing at minimum a "url" (wss-URI) and a "supportsPush" boolean.
The client MUST include the value "jmap" in the Sec-WebSocket-Protocol header. The server reply MUST also contain a Sec-WebSocket-Protocol header with value "jmap" for the subprotocol connection to be established.
The "maxConcurrentRequests" capability limit applies to requests made on the WebSocket connection. When using HTTP/2 multiplexing, this limit applies to the sum of requests on both the JMAP API endpoint and the WebSocket connection.
Upon receipt of a WebSocketPushEnable message containing a "pushState" token, the server SHOULD immediately send all changes since that state token.
A WebSocketPushDisable object sent by the client disables push notifications for the current connection. It has a single required field: "@type" which MUST be the string "WebSocketPushDisable".
A WebSocketPushEnable object sent by the client enables push notifications and has three fields: "@type" (MUST be "WebSocketPushEnable"), "dataTypes" (String[] or null to filter data type notifications), and optional "pushState" (last received pushState token).
The JMAP Request object is extended with two fields over WebSocket: "@type" (MUST be the string "Request") and an optional "id" (String) that the client uses to correlate out-of-order responses.
The JMAP Response object is extended with "@type" (MUST be "Response") and "requestId" (optional String; MUST be returned if an identifier was included in the request) to support out-of-order processing.
The Problem Details error object is extended with "@type" (MUST be "RequestError") and "requestId" (optional String; MUST be returned if given in the request) for request correlation over WebSocket.
The StateChange push notification object is extended with an optional "pushState" String field (a short token encoding the entire server state visible to the user) to allow efficient state resynchronization after reconnection.
The "urn:ietf:params:jmap:websocket" capability object has two fields: "url" (String, the wss-URI WebSocket endpoint) and "supportsPush" (Boolean, whether server-initiated push notifications are supported over WebSocket).
IANA has registered the WebSocket JMAP subprotocol in the "WebSocket Subprotocol Name Registry". Subprotocol Identifier: "jmap"; Common Name: "WebSocket Transport for JMAP (JSON Meta Application Protocol)"; Definition: RFC 8887.
JMAP over WebSocket can be used by both browser and non-browser clients. The security considerations in RFC 6455 Sections 10.2 (browser clients) and 10.1 (non-browser clients) apply to their respective environments.
To ensure confidentiality and integrity, the WebSocket connection MUST use TLS 1.2 or later following BCP 195 recommendations. Servers SHOULD support TLS 1.3 or later.