Skip to content

WebSocket Authentication

Authenticate the Rhombus event WebSocket: which credentials it accepts, where they go on the handshake, what a connection can see, partner connections, revocation, and how to read 401, 403 and 429 responses.

On this page

The event WebSocket (wss://ws.rhombussystems.com:8443/websocket) authenticates the HTTP upgrade request (the handshake). It accepts three credentials:

  • An API key, standard or partner, in a request header.
  • An OAuth access token with the read scope, as Authorization: Bearer <token>.
  • A federated token, as headers or query parameters. This is the one a browser can use.

Certificate (mTLS) keys aren't accepted on this connection.

Prerequisites

  • A credential:
  • A client that can send that credential. API keys and OAuth tokens travel in request headers, and browsers can't set headers on a WebSocket handshake, so a web app either connects from its backend and relays events, or opens the socket in the browser with a federated token in the URL (see Connecting from a browser).
Warning

Certificate (mTLS) keys aren't accepted on the event WebSocket. If your REST integration uses a certificate key, create a standard API key (Auth Type Api Token) for the WebSocket, or mint a federated token.

Generating an API token

  1. Log in to the Rhombus console
  2. Go to Settings → Integrations & Developer Resources → API Tokens and click Add API Key
  3. Enter a Name, set Auth Type to Api Token, and select a Role. The role decides which events the connection receives (see What a connection receives).
  4. Copy and securely store the token

Authentication parameters

Credentials go on the handshake (the HTTP upgrade request). Values sent later in the STOMP CONNECT frame (login, passcode or custom headers) are ignored.

Credentialx-auth-scheme (header or query parameter)Credential goes inWhere
API keyapi-tokenx-auth-apikeyHeader only
OAuth access tokenLeave it out, or api-oauth-tokenAuthorization: Bearer <token>Header only
Federated tokenfederated-tokenx-auth-ftHeader or query parameter

Partner credentials use the same schemes (partner-api-token and partner-api-oauth-token remain as aliases) and add one header:

NameWhereValueRequired
x-auth-orgHeader onlyThe client organization's UUIDYes, for every partner credential (see Partner API authentication)

An API key or OAuth token sent as a query parameter isn't read, and the handshake fails with 401.

Connection URL format

RegionURL
USwss://ws.rhombussystems.com:8443/websocket
EUwss://ws.eu.rhombussystems.com:8443/websocket

Use port 8443 and TLS 1.2 or later. Credentials are region-bound like every Rhombus credential, so an EU key or token only works on the EU host. See US & EU Regions.

API key

wss://ws.rhombussystems.com:8443/websocket?x-auth-scheme=api-token

Send the key in the x-auth-apikey header.

OAuth access token

wss://ws.rhombussystems.com:8443/websocket

Send Authorization: Bearer <access token>. A token whose grant doesn't include the read scope is refused with 403 PERMISSION_REQUIRED and WWW-Authenticate: Bearer error="insufficient_scope", scope="read".

Federated token

wss://ws.rhombussystems.com:8443/websocket?x-auth-scheme=federated-token&x-auth-ft=TOKEN

The token has the role of the credential that minted it. If it was minted with domain, the handshake's Origin must match that origin, or it's refused with 403 DOMAIN_NOT_ALLOWED.

Partner API token

wss://ws.rhombussystems.com:8443/websocket?x-auth-scheme=api-token

Send the partner key in x-auth-apikey and the client organization's UUID in the x-auth-org header. See Partner API authentication.

Authentication flow

1. Build the URL (x-auth-scheme as a query parameter or header)
         │
         ▼
2. Add the credential: x-auth-apikey, Authorization: Bearer, or x-auth-ft
   (and x-auth-org for partner credentials)
         │
         ▼
3. Open the WebSocket (wss, port 8443)
         │
    ┌────┴─────────────────────────┐
    ▼                              ▼
 Credentials accepted          Rejected before the upgrade:
    │                          401 (credential missing, unknown,
    ▼                               expired or revoked),
4. Send STOMP CONNECT          403 (valid credential, not allowed),
    │                          429 (rate limited)
    ▼
5. Receive STOMP CONNECTED → subscribe

No prior HTTP session is needed. The credential is checked at the handshake and again about once a minute while the connection is open (see Revocation).

Retrieving your organization UUID

Topic names include your organization UUID. Retrieve it with the REST API:

bash
curl -X POST https://api2.rhombussystems.com/api/org/getOrgV2 \
  -H "x-auth-scheme: api-token" \
  -H "x-auth-apikey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

The org UUID is at org.uuid in the response.

Example: Authenticated connection

import websocket

API_TOKEN = "YOUR_API_KEY"

url = "wss://ws.rhombussystems.com:8443/websocket?x-auth-scheme=api-token"
headers = {
    "x-auth-apikey": API_TOKEN
}

ws = websocket.create_connection(url, header=headers)
print("WebSocket connected")

Connecting from a browser

  • Use a federated token in the URL. Your backend mints it with generateFederatedSessionToken and hands it to the page, which opens the socket with x-auth-scheme=federated-token&x-auth-ft=<token> (see the browser example above). Mint it for the viewer's session (durationSec defaults to one hour and can't exceed 24 hours), read expiresAtMs from the response, and mint a new one before it expires. When the session ends, revoke it with POST /api/org/revokeFederatedSessionToken, from your backend or from the page, authenticated with the token itself. See Federated tokens.
  • Bind the token to your page with domain. A token minted with domain (an absolute origin such as https://app.example.com) is accepted only when the handshake's Origin matches it.
  • A signed-in Rhombus console session only works from the Rhombus console. A handshake that relies on the console's session cookies is accepted only from a Rhombus console origin, so a page on your own site can't use a viewer's console session. Handshakes with an API key, an OAuth token, a federated token or the Rhombus mobile app aren't origin-checked; a federated token's domain is its own origin check.

What a connection receives

  • Events are filtered by the credential's role. An API key uses its role. An OAuth token acts with the signed-in user's role, limited to the token's scopes. A federated token has the role of the credential that minted it. A full-access role receives every event in the organization. A role limited to some locations or devices receives only events for those; the rest are dropped without an error. If a connection is quiet, check the role before anything else.
  • Policy alerts follow the same rule. A policy alert is delivered when the role can access the alert's device or its location. An alert with neither goes only to full-access roles.
  • Entity types without an access check go only to full-access roles. A limited role receives the entity types the server can check against its devices and locations, and no others.
  • The connection is receive-only. Clients subscribe; they don't send commands over it. Use the REST API to act.
  • Subscribing to another organization's topic is refused. The server sends a STOMP ERROR frame and closes the socket with code 1002.

Partner API authentication

If you're a Rhombus partner receiving events for a client organization:

  1. Use your partner key with the api-token scheme (partner-api-token works as an alias)
  2. Send the client's orgUuid in the x-auth-org header. It's required: a partner credential without it is refused with 403 PERMISSION_REQUIRED. A blank value counts as absent, a query parameter isn't read, and a value that isn't a valid UUID gets 400 INVALID_AUTH_ORG.
  3. Open one connection per client organization; x-auth-org is fixed for the life of the connection
python
url = (
    "wss://ws.rhombussystems.com:8443/websocket"
    "?x-auth-scheme=api-token"
)
headers = {
    "x-auth-apikey": partner_api_token,
    "x-auth-org": client_org_uuid,
}

ws = websocket.create_connection(url, header=headers)

If your partner account isn't authorized for that client, the handshake fails with 403 PARTNER_CLIENT_ACCESS_DENIED.

Revocation

Deleting a key, changing its role, revoking an OAuth grant, or revoking a federated token (or the credential that minted it) takes effect within 60 seconds. An open connection that used the credential receives a STOMP ERROR frame and is closed with code 1008. After a role change, reconnecting picks up the new role. After a delete or revoke, every handshake with that credential fails with 401, so don't reconnect in a loop after a 1008: check the credential first.

Security best practices

  • Keep keys on your server. Never ship an API key to a browser or mobile app; relay events from your backend, or give the browser a short-lived federated token.
  • Use a dedicated credential with the narrowest role that still sees the devices you need. See Permissions and key rotation.
  • Ask only for the OAuth scopes you need. The event WebSocket needs read.
  • Reconnect with backoff. Handshakes count toward your organization's rate limit; a tight reconnect loop gets 429 responses.

Troubleshooting

A handshake refused before the upgrade returns an HTTP status, an x-rhombus-txid header and the same JSON body as every Rhombus host (see Errors):

json
{
  "msg": "x-auth-org is required for partner credentials",
  "error": true,
  "errorCode": "PERMISSION_REQUIRED",
  "errorMsg": "Your role does not have the required permission on the requested resource.",
  "status": 403,
  "timestamp": 1791367200000,
  "txid": "6f1c2a9e4b7d"
}

Read errorCode for the reason. Quote txid when you contact support.

ErrorCauseSolution
HTTP 401 UNAUTHENTICATEDNo credential reached the server: x-auth-scheme is missing, the key or OAuth token was sent as a query parameter, or the scheme is a certificate scheme (api, partner-api)Send the scheme and the credential as the table above shows
HTTP 401 INVALID_CREDENTIALThe key or token is malformed, unknown (a deleted API key, for example), or from the other regionUse an existing credential from the same region as the host
HTTP 401 CREDENTIAL_EXPIRED or CREDENTIAL_REVOKEDThe key or token expired, or it was revoked (an OAuth token whose grant was revoked, for example)Create a new key, refresh or re-authorize the OAuth token, or mint a new federated token
HTTP 401 CERTIFICATE_MISMATCHA certificate key was sent with api-tokenUse a standard API key (Auth Type Api Token)
HTTP 403 PERMISSION_REQUIREDA partner credential without x-auth-org, or an OAuth token without the read scope (the response names the scope in WWW-Authenticate)Send x-auth-org; ask the user to authorize the read scope
HTTP 403 PARTNER_CLIENT_ACCESS_DENIEDThe partner isn't authorized for the x-auth-org organizationCheck the partner's access to the client
HTTP 403 DOMAIN_NOT_ALLOWEDA federated token minted with domain, opened from another originMint the token with your page's exact origin
HTTP 400 INVALID_AUTH_ORGx-auth-org isn't a valid organization UUIDSend the client organization's UUID
HTTP 429 RATE_LIMITEDToo many handshakes or API calls for the organizationWait for Retry-After seconds, then reconnect with backoff
Connected, but no events arriveThe credential's role doesn't cover the devices or locationsUse a role that covers the devices (see What a connection receives)
STOMP ERROR and close code 1008The credential was deleted, revoked or had its role changed while connectedCheck the credential before reconnecting (see Revocation)
STOMP ERROR and close code 1002Subscribed to a topic outside the credential's organization, or sent a frame the server doesn't acceptSubscribe with the organization UUID the credential belongs to (or the x-auth-org client)
Connection drops after about 30 secondsNo heartbeatsSend STOMP heartbeats (see Connection Lifecycle)
Connection timeoutNetwork or firewallAllow outbound TLS to port 8443