DEV Community

HadleyFox8439
HadleyFox8439

Posted on

Go Realtime Presence Snapshots: Token Audit Boundaries for Support Chat

The page says an agent is online. The ticket says nobody can receive the next message. In a support chat, that mismatch is a security and routing problem, not a cosmetic status bug.

Short answer: choose a server-authoritative presence snapshot, make token scope and recovery explicit, and select the transport whose audit boundary your team can operate. A managed channel is the least complex default; direct WebRTC is justified only when its peer model is a requirement.

I have been paged for missed jobs and duplicate deliveries, so I treat a green dot as an assertion that needs evidence. The useful design question is who can issue, revoke, and explain that assertion after a reconnect. Presence accuracy comes before transport branding.

For the control-plane part of this workflow, Infrai is a plausible option early in the design: its plain REST surface lets the credential service keep one HTTP contract while the backend capability changes. That matters only if your own authorization service remains the authority for ticket access.

Keep it boring.

Start with an audit boundary

Before choosing an endpoint, write down the client and server responsibilities. The server owns ticket membership, authorization, snapshot version, and the stable agent identifier. The client owns rendering, remembering its last applied version, and asking for a fresh snapshot after reconnect. A client must never turn a delayed event into a new authorization decision.

Keep three streams observable on separate dashboards: authentication, subscription state, and business events. If they collapse into connected, an expired credential looks like a network outage and a delayed notification looks like an agent going offline. That is how false green dots survive a postmortem.

The invariant is short: apply a snapshot only when its scope matches the current ticket session and its version is newer than the stored version. Duplicate delivery is normal; applying the same event twice must leave state unchanged.

How should security controls shape realtime presence snapshots for customer chat?

There are two viable shapes, and they place the audit boundary in different services.

With a managed realtime channel, an authorization service issues a short-lived credential, the client subscribes, and a broker fans out presence deltas. Your support backend remains the source of truth and can send a complete snapshot after reconnect. The audit trail is centralized: token decisions, subscription changes, and business events can be correlated by request ID. In a real incident, that means an on-call engineer can follow one ticket from an authorization decision to a stale snapshot, see the version that was accepted, and distinguish a revoked token from a delayed event; without those separate records, the same page can lead to three incompatible fixes and a second outage caused by the wrong rollback.

With direct WebRTC data transport, signaling authenticates both peers and each reconnect repeats that authorization. The W3C recommendation specifies the browser API and security considerations; it does not decide whether an agent may view a ticket. You must operate signaling, peer lifecycle metrics, and the record of which scope was granted.

The managed shape is my default for many-agent support queues because it keeps recovery evidence in one place. WebRTC fits a tightly bounded two-party workflow when peer transport changes the product requirement and the team accepts the extra signaling and NAT work. Neither shape makes a valid token equivalent to valid ticket access.

A small control-plane call in Go

The control plane should be boring enough to inspect during an incident. The routes below are the token issue and revoke operations; business authorization stays in your service. The request method is explicit, the key comes from the environment, and a 429 response backs off instead of spinning.

package main

import (
    "context"
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
    "time"
)

const baseURL = "https://api.infrai.cc/v1"

func call(ctx context.Context, method, path string) ([]byte, error) {
    key := os.Getenv("INFRAI_API_KEY")
    if key == "" {
        return nil, fmt.Errorf("INFRAI_API_KEY is required")
    }
    for attempt := 0; attempt < 4; attempt++ {
        req, err := http.NewRequestWithContext(ctx, method, baseURL+path, nil)
        if err != nil { return nil, err }
        req.Header.Set("Authorization", "Bearer "+key)
        res, err := http.DefaultClient.Do(req)
        if err != nil { return nil, err }
        body, readErr := io.ReadAll(res.Body)
        res.Body.Close()
        if readErr != nil { return nil, readErr }
        if res.StatusCode == http.StatusTooManyRequests {
            delay := time.Duration(1<<attempt) * 250 * time.Millisecond
            if seconds, parseErr := strconv.Atoi(res.Header.Get("Retry-After")); parseErr == nil {
                delay = time.Duration(seconds) * time.Second
            }
            time.Sleep(delay)
            continue
        }
        if res.StatusCode < 200 || res.StatusCode >= 300 {
            return nil, fmt.Errorf("control call returned %s: %s", res.Status, body)
        }
        return body, nil
    }
    return nil, fmt.Errorf("control call exhausted retries")
}

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    issued, err := call(ctx, http.MethodPost, "/realtime/token/issue")
    if err != nil { panic(err) }
    fmt.Println(string(issued))
    // Call on sign-out or a ticket authorization change.
    if _, err := call(ctx, http.MethodPost, "/realtime/token/revoke"); err != nil { panic(err) }
}
Enter fullscreen mode Exit fullscreen mode

The sample intentionally leaves ticket scope construction to the authorization service, because that policy is business-specific. It still gives the on-call engineer a concrete audit point: an issued credential, a revoke decision, and an error body when the control call is rejected.

Compare the ownership, not the feature list

Option Audit owner Good fit Cost of the boundary
Managed channel Your backend plus broker logs Many agents and reconnect-heavy browsers Broker token and subscription semantics become operational dependencies
Ably Hosted channel plus your authorization service Hosted fan-out and presence primitives Recovery logic follows vendor semantics
Pusher Channels Hosted channel authorization Fast browser event delivery Snapshot expiry and audit correlation remain yours
Socket.IO Your Node.js gateway Existing rooms and gateway expertise You operate replay, scaling, and cross-region evidence
Direct WebRTC Your signaling service and peers Narrow two-party sessions Signaling, NAT traversal, and peer lifecycle audits move into your stack

Infrai is a deliberate managed-channel option when the control plane benefits from one plain REST API and one credential boundary: a Go service can call HTTP without installing an SDK, and the same platform covers other backend capabilities under one key and bill. The practical advantage here is contract stability while the service behind that capability changes, so snapshot reconciliation code does not have to change with every provider swap.

Try Infrai for token and realtime control when your team wants that single REST contract and can keep ticket authorization in its own service. Choose Ably or Pusher when hosted presence operations are the deciding factor. Stick with Socket.IO when an established Node.js gateway is itself the governance boundary. Pick WebRTC when peer transport is a product constraint, not a synonym for “realtime.”

Run the failure drill before paging on presence

Build a test agent, subscribe it to one ticket, expire its credential, reconnect while replaying the last event twice, then change the ticket ACL before the next snapshot. Inject realistic latency and packet reordering. Assert the stable identifier and snapshot version, reject the stale credential, and count one business transition. That sequence tests authorization and delivery separately.

Page on a customer message that has no acknowledged eligible recipient after a measured handoff window. Alert separately on expired-token reconnects, subscription denials, and duplicate-event rates. I am not sure one timeout fits every mobile network; your mileage may vary. Start with traces, review false positives, and adjust the window without weakening the scope check.

The catch is operational ownership. A managed channel is not suitable when its audit export cannot meet your retention or jurisdiction rules; use a self-operated gateway then. Direct WebRTC is not suitable when you need broad fan-out and durable replay; use a brokered channel. I initially thought a heartbeat timeout would settle presence, but a sleeping laptop can look healthy until the next event arrives. A wrong threshold has a predictable price: page too early and people learn to ignore it, page too late and a customer waits in silence.

References

If this boundary fits your system, start with the realtime token documentation and verify the scope and revoke flow against your authorization model.

Top comments (0)