Production deployments authenticate via OpenID Connect (OIDC) using Keycloak. End users
sign in through the application's
/login/index.html page, which obtains and refreshes
access tokens automatically.
For local development or migration, a legacy OAuth2 password grant is available at
POST /api/auth/token when
SQUAWK_STUB_AUTH_ENABLED=true. It accepts
application/x-www-form-urlencoded data with
grant_type=password,
username, and
password.
You can inspect the current user's roles and identity via
GET /api/auth/me.
Append ?token=<jwt> to the WebSocket URL:
const wsUrl = 'wss://example.com/api/ws?token=' + encodeURIComponent(token) const client = new SquawkWebSocket(wsUrl, audioContext)
Include an
Authorization: Bearer <jwt> header. The
built-in API client adds this header automatically once a user is authenticated.
The easiest way to integrate with Squawk is using the
SquawkWebSocket library. This standalone ES module
handles WebSocket connections, audio playback, and stream management.
https://example.com/lib/listener_websocket.js
import { SquawkWebSocket } from 'https://example.com/lib/listener_websocket.js' const token = 'your_jwt_token' const audioContext = new (window.AudioContext || window.webkitAudioContext)() const client = new SquawkWebSocket('wss://example.com/api/ws?token=' + encodeURIComponent(token), audioContext) client.on('connected', () => { console.log('Connected!') client.subscribe(['asset:equities']) }) client.on('stream_start', (msg) => { console.log('Stream started:', msg.keywords) }) client.connect()
new SquawkWebSocket(url: string, audioContext: AudioContext)
| Parameter | Type | Required | Description |
|---|---|---|---|
url |
string | Required | WebSocket endpoint URL |
audioContext |
AudioContext | Required | Browser AudioContext instance for audio playback |
| Method | Parameters | Description |
|---|---|---|
connect() |
none | Connect to the WebSocket server |
disconnect() |
none | Disconnect from the server |
subscribe() |
keywords: string[] | Subscribe to keywords |
unsubscribe() |
keywords: string[] | Unsubscribe from keywords |
ping() |
none | Send a keepalive ping |
get_status() |
none | Get current connection status |
unlock_audio() |
none | Unlock audio after user gesture (call in response to click/tap) |
is_audio_locked() |
none | Check if audio is locked due to autoplay policy |
on() |
event: string, handler: function |
Listen for events |
| Event | Data | Description |
|---|---|---|
connected |
none | WebSocket connected |
disconnected |
CloseEvent |
WebSocket disconnected. Check event.code — 4003 means auth failed
|
stream_start |
StreamStartMessage | Audio stream started (receives StreamStartMessage) |
stream_end |
{ session_id: string } | Audio stream ended |
subscribed |
{ keywords: string[] } | Subscription confirmed |
clip_received |
ClipMessage | Historical clip received |
audio_locked |
none | Autoplay blocked - user interaction needed. Call unlock_audio() after user gesture. |
audio_unlocked |
none | Audio successfully unlocked after user interaction |
error |
Error | Error occurred |
status_change |
ConnectionStatus | Connection status changed |
/api/ws
Connect to this endpoint to establish a WebSocket connection for receiving audio streams. The server accepts text commands (JSON) and sends both text messages (JSON metadata) and binary messages (audio data).
Subscribe to one or more keywords to receive matching audio streams.
{ "type": "subscribe", "keywords": ["asset:equities", "region:us"] }
Remove subscriptions for specific keywords.
{ "type": "unsubscribe", "keywords": ["asset:equities"] }
Keep the connection alive. The server will respond with a
pong.
{ "type": "ping" }
Sent when a broadcaster starts streaming audio matching your subscribed keywords.
{ "type": "stream_start", "session_id": "550e8400-e29b-41d4-a716-446655440000", "keywords": ["asset:equities"], "content_type": "audio/webm;codecs=opus", "timestamp": "2024-01-15T10:30:00Z" }
Sent when the broadcaster stops streaming.
{ "type": "stream_end", "session_id": "550e8400-e29b-41d4-a716-446655440000" }
Sent when a historical clip is available. Followed by binary audio data.
{ "type": "clip", "clip_id": "clip-123", "keywords": ["asset:equities"], "content_type": "audio/webm", "size_bytes": 102456, "timestamp": "2024-01-15T10:00:00Z" }
Confirmation that your subscription was registered.
{ "type": "subscribed", "keywords": ["asset:equities"] }
Sent when an error occurs.
{ "type": "error", "message": "Invalid message format" }
After a stream_start message, the server sends
binary audio chunks as ArrayBuffer messages. The
SquawkWebSocket library automatically handles these and feeds them to the audio element.
Similarly, after a clip message, the next binary
message contains the complete clip audio data.
This demo uses the SquawkWebSocket library to
connect to /api/ws and subscribes to
asset:equities. When a broadcaster transmits with this
keyword, audio will play automatically.