WebSocket Destination¶
Stream Keycloak events to WebSocket servers.
| Property | Value |
|---|---|
destination.kind |
websocket |
| Protocol | WebSocket (RFC 6455) |
Compatible Systems¶
| System | Notes |
|---|---|
| Eclipse Mosquitto | MQTT over WebSocket (port 9001) |
| HiveMQ | MQTT over WebSocket |
| EMQX | MQTT over WebSocket (port 8083/8084) |
| VerneMQ | MQTT over WebSocket |
| RabbitMQ | Via rabbitmq_web_stomp or rabbitmq_web_mqtt plugins |
| Azure Web PubSub | Managed WebSocket service |
| Azure Event Grid | WebSocket support for MQTT |
| Any WebSocket server | Standard RFC 6455 compatible |
| Custom backends | Node.js, Python, Go, Java WebSocket servers |
| Real-time dashboards | Live event monitoring applications |
| Browser applications | Via WebSocket-to-browser bridges |
| API Gateways | Kong, AWS API Gateway WebSocket APIs |
| Serverless | AWS API Gateway WebSocket, Azure Web PubSub |
WebSocket vs Native Protocol
Many message brokers support WebSocket as a transport layer for their native protocol (e.g., MQTT over WebSocket, STOMP over WebSocket). KETE's WebSocket destination sends raw messages directly to WebSocket endpoints, which is ideal for custom backends and dashboards. For broker integrations, consider using the native protocol destination (e.g., mqtt-3, stomp) with the broker's WebSocket port.
Example Configurations¶
kete.routes.oauth-ws.realm-matchers.realm=list:master
kete.routes.oauth-ws.destination.kind=websocket
kete.routes.oauth-ws.destination.url=wss://api.example.com/events
kete.routes.oauth-ws.destination.oauth.enabled=true
kete.routes.oauth-ws.destination.oauth.token-url=https://auth.example.com/oauth/token
kete.routes.oauth-ws.destination.oauth.client-id=keycloak-client
kete.routes.oauth-ws.destination.oauth.client-secret=secret
kete.routes.oauth-ws.destination.oauth.scope=events:write
# Uses Keycloak itself as OAuth server - auto-creates client!
kete.routes.internal-oauth-ws.realm-matchers.realm=list:master
kete.routes.internal-oauth-ws.destination.kind=websocket
kete.routes.internal-oauth-ws.destination.url=wss://api.example.com/events
kete.routes.internal-oauth-ws.destination.oauth.enabled=true
kete.routes.internal-oauth-ws.destination.oauth.mode=internal
Features¶
- ✅ Text and binary message modes
- ✅ TLS/SSL support with mutual TLS (mTLS)
- ✅ OAuth 2.0 Client Credentials with token caching
- ✅ Custom headers for authentication
- ✅ Automatic reconnection on connection loss
- ✅ Configurable connection timeout
- ✅ Ping/pong heartbeat for connection health detection
Configuration Properties¶
Required Properties¶
| Property | Description | Example |
|---|---|---|
destination.kind |
Must be websocket |
websocket |
destination.url |
Full WebSocket URL (supports templating) | ws://server:8080/events/${realmLowerCase} |
Dynamic URLs (Templating)¶
The url property supports template variables:
# Dynamic URL per realm
kete.routes.ws.destination.url=ws://websocket-server.example.com:8080/events/${realmLowerCase}
# Dynamic URL with event type
kete.routes.ws.destination.url=ws://websocket-server.example.com/${kindLowerCase}/${eventTypeLowerCase}
Available variables: ${realmLowerCase}, ${realmUpperCase}, ${eventTypeLowerCase}, ${eventTypeUpperCase}, ${kindLowerCase}, ${kindUpperCase}, ${resourceTypeLowerCase}, ${resourceTypeUpperCase}, ${operationTypeLowerCase}, ${operationTypeUpperCase}, ${resultLowerCase}, ${resultUpperCase}
When using destination.url:
- The scheme must be
ws://orwss:// - TLS is auto-enabled when the scheme is
wss:// - The host, port, and path are extracted from the URL
- The path and query string can include template variables for dynamic routing
If both url and individual properties are specified, url takes precedence.
Alternative: Individual Properties¶
| Property | Description | Example |
|---|---|---|
destination.host |
WebSocket server hostname (if no url) |
websocket.example.com |
Optional Properties¶
| Property | Default | Description | Example |
|---|---|---|---|
destination.port |
80 (WS) / 443 (WSS) |
WebSocket server port | 8080 |
destination.path |
/ |
URL path | /events |
destination.binary-mode |
false |
Send as binary frames (not text) | true |
destination.connection-timeout-seconds |
10 |
Connection timeout in seconds | 30 |
destination.connection-lost-timeout-seconds |
60 |
Heartbeat timeout in seconds (0 = disabled). Uses WebSocket ping/pong to detect dead connections. | 30 |
destination.pool.min-idle |
1 |
Minimum idle connections in pool | 5 |
destination.pool.max-idle |
10 |
Maximum idle connections in pool | 20 |
destination.pool.max-total |
20 |
Maximum total connections in pool | 50 |
Custom Headers¶
Headers are configured under destination.headers.<NAME>:
kete.routes.ws.destination.headers.Authorization=Bearer my-token
kete.routes.ws.destination.headers.X-Custom-Header=value
OAuth 2.0 Properties¶
The WebSocket destination supports two OAuth modes:
External Mode (Default)¶
Use an external OAuth 2.0 authorization server:
| Property | Required | Default | Description |
|---|---|---|---|
destination.oauth.enabled |
No | false |
Enable OAuth 2.0 Client Credentials flow |
destination.oauth.mode |
No | external |
OAuth mode: external or internal |
destination.oauth.token-url |
Yes* | - | OAuth token endpoint URL |
destination.oauth.client-id |
Yes* | - | OAuth client ID |
destination.oauth.client-secret |
Yes* | - | OAuth client secret |
destination.oauth.scope |
No | "" |
Requested OAuth scopes (space-separated) |
*Required when oauth.enabled=true and oauth.mode=external.
Internal Mode¶
Use the current Keycloak instance as the OAuth server. This mode automatically registers a service account client in Keycloak during initialization - the simplest setup possible:
| Property | Required | Default | Description |
|---|---|---|---|
destination.oauth.enabled |
Yes | false |
Enable OAuth 2.0 |
destination.oauth.mode |
Yes | - | Must be internal |
destination.oauth.realm |
No | Route realm | Override realm for token URL |
destination.oauth.client-id |
No | kete-oauth-client |
Override auto-generated client ID |
destination.oauth.client-secret |
No | Auto-generated | Override auto-generated secret |
destination.oauth.scope |
No | "" |
Requested OAuth scopes |
Internal Mode Example:
# Simplest OAuth setup - just 2 properties!
kete.routes.ws.destination.oauth.enabled=true
kete.routes.ws.destination.oauth.mode=internal
This automatically:
- Creates a confidential client
kete-oauth-clientin the route's realm - Enables service account (client credentials grant)
- Generates a secure client secret
- Configures the token URL for the realm
TLS Properties¶
See TLS & mTLS for full details on TLS options.
| Property | Default | Description |
|---|---|---|
destination.tls.enabled |
false |
Enable WSS (auto-enabled when using wss:// URL) |
destination.tls.key-store.* |
- | Client certificate for mTLS |
destination.tls.trust-store.* |
- | CA certificates |
Message Format¶
Messages are sent as either:
- Text frames (default): UTF-8 encoded JSON from the serializer
- Binary frames (when
binary-mode=true): Raw bytes from the serializer
The message content is the serialized event (JSON, XML, etc. based on your serializer configuration).
Configuration Examples¶
Basic WebSocket¶
kete.routes.ws.destination.kind=websocket
kete.routes.ws.realm-matchers.realm=list:master
kete.routes.ws.destination.url=ws://websocket-server:8080/events
Secure WebSocket with Authentication¶
kete.routes.secure-ws.destination.kind=websocket
kete.routes.secure-ws.realm-matchers.realm=list:master
kete.routes.secure-ws.destination.url=wss://api.example.com/events
kete.routes.secure-ws.destination.headers.Authorization=Bearer eyJhbGc...
kete.routes.secure-ws.destination.tls.trust-store.path=/certs/ca.pem
With OAuth 2.0¶
kete.routes.oauth-ws.destination.kind=websocket
kete.routes.oauth-ws.realm-matchers.realm=list:master
kete.routes.oauth-ws.destination.url=wss://api.example.com/events
kete.routes.oauth-ws.destination.oauth.enabled=true
kete.routes.oauth-ws.destination.oauth.token-url=https://auth.example.com/oauth/token
kete.routes.oauth-ws.destination.oauth.client-id=keycloak-client
kete.routes.oauth-ws.destination.oauth.client-secret=secret