Overview

Azure Web PubSub Service provides an easy way to publish/subscribe messages using simple WebSocket connections.

  1. Client can be written in any language having WebSocket support
  2. Both text and binary messages are supported within one connection
  3. A simple protocol for clients to do direct client-client message publish
  4. The service manages the WebSocket connections for you

Table of Content

Terms

  • Service: Azure Web PubSub Service.

  • Hub: A logic isolation for one application. Different applications can share one Azure Web PubSub service by using different hub names.

  • Group: Clients can join a group, leave a group, or publish messages to a group. A client can join multiple groups, and a group can contain multiple clients.

  • Client Connection and ConnectionId: A client connects to the /client endpoint, when connected, a unique connectionId is generated by the service as the unique identity of the client connection. Users can then manage the client connection using this connectionId. Details are described in Client Protocol section.

  • Client Events: Events are created during the lifecycle of a client connection. For example, a simple WebSocket client connection creates a connect event when it tries to connect to the service, a connected event when it successfully connected to the service, a message event when it sends messages to the service and a disconnected event when it disconnects from the service. Details about client events are illustrated in Client Protocol section.

  • Event Handler: The event handler contains the logic to handle the client events. Event handler needs to be registered and configured in the service through the portal or Azure CLI beforehand. Details are described in Event Handler section. The place to host the event handler logic is generally considered as the server-side.

  • Server: The server can handle client events, manage client connections, and publish messages to groups. The server, comparing to the client, is trustworthy. Details about server are described in Server Protocol section.

Workflow

Workflow

As illustrated by the above workflow graph:

  1. A client connects to the service /client endpoint using WebSocket transport. Service forward every WebSocket frame to the configured upstream(server). The WebSocket connection can connect with any custom subprotocol for the server to handle, or it can connect with the service-supported subprotocol json.webpubsub.azure.v1 which empowered the clients to do pub/sub directly. Details are described in client protocol.
  2. The service invokes the server using CloudEvents HTTP protocol on different client events. CloudEvents is a standardized and protocol-agnostic definition of the structure and metadata description of events hosted by the Cloud Native Computing Foundation (CNCF). Details are described in server protocol.
  3. Server can invoke the service using REST API to send messages to clients or to manage the connected clients. Details are described in server protocol

Client Protocol

A client connection connects to the /client endpoint of the service using WebSocket protocol. The WebSocket protocol provides full-duplex communication channels over a single TCP connection and was standardized by the IETF as RFC 6455 in 2011. Most languages have native support to start WebSocket connections.

Our service supports two kinds of clients:

  1. One is called the simple WebSocket client
  2. The other is called the PubSub WebSocket client

The simple WebSocket client

A simple WebSocket client, as the naming indicates, is a simple WebSocket connection. It can also have its custom subprotocol.

For example, in JS, a simple WebSocket client can be created using:

// simple WebSocket client1
var client1 = new WebSocket('wss://test.webpubsub.azure.com/client/hubs/hub1');

// simple WebSocket client2 with some custom subprotocol
var client2 = new WebSocket('wss://test.webpubsub.azure.com/client/hubs/hub1', 'custom.subprotocol')

A simple WebSocket client follows a client<->server architecture, as the below sequence diagram shows: Simple Client Sequence

  1. When the client starts WebSocket handshake, the service tries to invoke the connect event handler (the server) for WebSocket handshake. Users can use this handler to handle the WebSocket handshake, determine the subprotocol to use, auth the client, and join the client to some groups.
  2. When the client is successfully connected, the service invokes a connected event handler. It works as some notification and does not block the client from sending messages. Users can use this handler to do some data storage and can respond with messages sending to the client.
  3. When the client sends messages, the services triggers the message event to the event handler (the server) to handle the messages sent. This is a general event containing the messages sent in a WebSocket frame. User needs to dispatch the messages on their own inside this event handler.
  4. When the client disconnects, the service tries to trigger the disconnected event to the event handler (the server) once it detects the disconnect.

The events fall into 2 categories:

  • synchronous events (blocking) Synchronous events block the client workflow. When such an event trigger fails, the service drops the client connection.
    • connect
    • message
  • asynchronous events (non-blocking) Asynchronous events do not block the client workflow, it acts as some notification to the upstream event handler. When such an event trigger fails, the service logs the error detail.
    • connected
    • disconnected

Scenarios:

Such connection can be used in a typical client-server architecture, that the client sends messages to the server, and the server handles incoming messages using Event Handlers. It can also be used when customers leverage existing subprotocols in their application logic.

The PubSub WebSocket client

The service also supports a specific subprotocol called json.webpubsub.azure.v1 which empowers the clients to do publish/subscribe directly instead of a round trip to the upstream server. We call the WebSocket connection with json.webpubsub.azure.v1 subprotocol a PubSub WebSocket client.

For example, in JS, a PubSub WebSocket client can be created using:

// PubSub WebSocket client
var pubsub = new WebSocket('wss://test.webpubsub.azure.com/client/hubs/hub1', 'json.webpubsub.azure.v1');

A PubSub WebSocket client has the ability to :

  • Join a group, for example:
      {
          "type": "joinGroup",
          "group": "<group_name>"
      }
    
  • Leave a group, for example:
      {
          "type": "leaveGroup",
          "group": "<group_name>"
      }
    
  • Publish messages to a group, for example:
      {
          "type": "sendToGroup",
          "group": "<group_name>",
          "data": { "hello": "world" }
      }
    
  • Send custom events to the upstream server, for example:

      {
          "type": "event",
          "event": "<event_name>",
          "data": { "hello": "world" }
      }
    

PubSub WebSocket Subprotocol contains the details of the json.webpubsub.azure.v1 subprotocol.

You may have noticed that for a simple WebSocket client, the server is a MUST HAVE role to handle the events from clients. A simple WebSocket connection always triggers a message event when it sends messages, and always relies on the server-side to process messages and do other operations. With the help of the json.webpubsub.azure.v1 subprotocol, an authorized client can join a group and publish messages to a group directly. It can also route messages to different upstreams (event handlers) by customizing the event the message belongs.

Scenarios:

Such clients can be used when clients want to talk to each other. Messages are sent from client1 to the service and the service delivers the message directly to client2 if the clients are authorized to do so.

Client1:

var client1 = new WebSocket("wss://xxx.webpubsub.azure.com/client/hubs/hub1", "json.webpubsub.azure.v1");
client1.onmessage = e => {
    if (e.data) {
        var message = JSON.parse(e.data);
        if (message.type === "message" 
        && message.group === "Group1"){
            // Only print messages from Group1
            console.log(message.data);
        }
    }
};

client1.onopen = e => {
    client1.send(JSON.stringify({
        type: "joinGroup",
        group: "Group1"
    }));
};

Client2:

var client2 = new WebSocket("wss://xxx.webpubsub.azure.com/client/hubs/hub1", "json.webpubsub.azure.v1");
client2.onopen = e => {
    client2.send(JSON.stringify({
        type: "sendToGroup",
        group: "Group1",
        data: "Hello Client1"
    });
};

As the above example shows, client2 sends data directly to client1 by publishing messages to Group1 which client1 is in.

Client message limit

The maximum allowed message size for one WebSocket frame is 1MB.

Client Auth

Auth workflow

Client uses a signed JWT token to connect to the service. The upstream can also reject the client when it is connect event handler of the incoming client. The event handler can auth the client by specifying the userId and the roles the client has in the webhook response, or decline the client with 401. Event handler section describes it in detail.

The below graph describes the workflow:

Client Connect Workflow

As you may have noticed when we describe the PubSub WebSocket clients, that a client can publish to other clients only when it is authorized to. The roles of the client determines the initial permissions the client have:

Role Permission
Not specified The client can send events.
webpubsub.joinLeaveGroup The client can join/leave any group.
webpubsub.sendToGroup The client can publish messages to any group.
webpubsub.joinLeaveGroup.<group> The client can join/leave group <group>.
webpubsub.sendToGroup.<group> The client can publish messages to group <group>.

The server-side can also grant or revoke permissions of the client dynamically through server protocol as to be illustrated in a later section.

Server Protocol

Server protocol provides the functionality for the server to manage the client connections and the groups.

In general, server protocol contains 2 roles:

  1. Event handler
  2. Connection manager

Event handler

The event handler handles the incoming client events. Event handlers need to be registered and configured in the service through portal or Azure CLI beforehand so that when a client event is triggered, the service can identify if the event is expected to be handled or not. For public preview, we use PUSH mode to invoke the event handler: that the event handler as the server side, exposes public accessible endpoint for the service to invoke when the event is triggered. It acts as a webhook.

Service delivers client events to the upstream webhook using the CloudEvents HTTP protocol.

For every event, it formulates an HTTP POST request to the registered upstream and expects an HTTP response.

The data sending from the service to the server is always in CloudEvents binary format.

Event PUSH

Upstream and Validation

Event handlers need to be registered and configured in the service through portal or Azure CLI beforehand so that when a client event is triggered, the service can identify if the event is expected to be handled or not. For public preview, we use PUSH mode to invoke the event handler: that the event handler as the server side, exposes public accessible endpoint for the service to invoke when the event is triggered. It acts as a webhook upstream.

When configuring the webhook endpoint, the URL can use {event} parameter to define an URL template. The service calculates the value of the webhook URL dynamically when the client request comes in. For example, when a request /client/hubs/chat comes in, with a configured event handler URL pattern http://host.com/api/{event} for hub chat, when the client connects, it will first POST to this URL: http://host.com/api/connect. This can be extremely useful when a PubSub WebSocket client sends custom events, that the event handler helps dispatch different events to different upstreams. Please NOTE that the {event} parameter is not allowed in the URL domain name.

When setting up the event handler upstream through Azure portal or CLI, the service follows the CloudEvents abuse protection to validate the upstream webhook. The WebHook-Request-Origin request header is set to the service domain name xxx.webpubsub.azure.com, and it expects the response having header WebHook-Allowed-Origin to contain this domain name.

When doing the validation, the {event} parameter is resolved to validate. For example, when trying to set the URL to http://host.com/api/{event}, the service tries to OPTIONS a request to http://host.com/api/validate and only when the response is valid that the configure can be set successfully.

For now , we do not support WebHook-Request-Rate and WebHook-Request-Callback.

Authentication between service and webhook

  1. Anonymous mode
  2. Simple Auth that code is provided through the configured Webhook URL.
  3. AAD Auth.
    1. Add a client secret in AAD’s [App Registrations] and provide the [client secret] to Azure Web PubSub through portal/cli.
    2. Provide the Identity to Azure Web PubSub through portal/cli

Connection manager

The server is by nature an authorized user. With the help of the event handler role, the server knows the metadata of the clients, for example, connectionId and userId, so it can:

  1. Close a client connection
  2. Send messages to a client
  3. Send messages to clients that belong to the same user
  4. Add a client to a group
  5. Add clients authed as the same user to a group
  6. Remove a client from a group
  7. Remove clients authed as the same user from a group
  8. Publish messages to a group

It can also grant or revoke publish/join permissions for a PubSub client:

  1. Grant Join/Publish permissions to some specific group or to all groups
  2. Revoke Join/Publish permissions for some specific group or for all groups
  3. Check if the client has permission to Join/Publish to some specific group or to all groups

For public preview, the service provides REST APIs for the server to do connection management:

Manager REST

The detailed REST API protocol is defined here.

Summary

You may have noticed that the event handler role handles communication from the service to the server while the manager role handles communication from the server to the service. So combing the two roles, the data flow between service and server looks as similar to below, leveraging HTTP protocol:

HTTP Protocol

Find an issue? Please report it here. Your feedback is highly appreciated! Provide it via Azure Feedback Forum.