Skip to main content

Embedded STUN Responder

AuthProxy ships with a built-in STUN responder for WebRTC NAT traversal. Instead of depending on stun.l.google.com:19302 (which is blocked in some networks) every customer deployment can list its own AuthProxy as a STUN server in WebRTC iceServers and the call flow keeps working without an extra service.

The responder is the absolute minimum needed for STUN binding requests: parse the request, return the reflexive transport address, increment counters. It is not a full coturn replacement (no TURN allocation, no long-term credentials).

Bind topology

The responder binds UDP on the same port AuthProxy uses for HTTP/HTTPS — the rationale is that WebRTC clients often have outbound UDP allowed on :443 even when arbitrary high ports are blocked.

+------------------------+
| AuthProxy process |
| TCP :8081 HTTPS web | <-- Razor pages, /auth/v1/*, /payorders/v1/*, ...
| UDP :8081 STUN bind | <-- STUN binding requests
+------------------------+

The actual port is resolved from same_web_port in config. IPv4 only in V1 — IPv6 binding is best-effort and is silently skipped if it fails.

API surface

Authenticated diagnostics

MethodPathPurpose
POST/auth/v1/stun/reportStore the current client's WebRTC diagnostics (ClientStunDiagnosticReport: stage, connection / ICE / signaling states, local & remote candidate types, selected-pair RTT, bytes sent/received) and return a merged server snapshot.
GET/auth/v1/stun/current?callId=...Return the merged client-side and server-side diagnostics for the active session.

Both endpoints require a valid session cookie (or X-Crm header in Local / Development / Test environments). The merged response includes server counters (packetsReceived, responsesSent, invalidPackets, lastSuccessAtUtc, etc.) so operators can correlate browser-side issues with server-side traffic without enabling debug logs.

The ProxyAdmin panel at /ProxyAdmin/StunMonitor exposes the same snapshot to operators.

Public STUN traffic

The STUN protocol itself is served on UDP — there is no HTTP endpoint. WebRTC clients add the responder to their iceServers array:

const pc = new RTCPeerConnection({
iceServers: [
{ urls: ['stun:authproxy.example.com:8081'] },
// optional fallbacks:
{ urls: ['stun:stun.l.google.com:19302'] },
],
});

When to use it

ScenarioRecommended setup
Production with reliable Google STUN reachabilityKeep Google STUN as primary, embedded as fallback.
Networks that block public STUN (corporate, certain countries)Embedded STUN as primary, customer-owned coturn / Google STUN as fallback.
Dev / stagingUse only embedded STUN to avoid dependence on external services.

The Chat module already lists embedded STUN among the fallback servers in its WebRTC config; see the platform CHAT-OVERVIEW.md for the full call-side flow.

Operational signals

  • Process startup: log line STUN responder bound on udp/<port> (or STUN responder soft-failed on udp/<port> when binding is impossible — the rest of AuthProxy continues to start).
  • Per-packet counters: snapshot is updated on every binding request and is observable through GET /auth/v1/stun/current and /ProxyAdmin/StunMonitor.
  • Tracing: relevant Activity is emitted under stun.bind.request so spans can be correlated with the originating call from chat.pwa.

Security

The current model is permissive — any UDP source can hit the responder. A more restrictive access model (recent-auth IP allowlist / active-call window / internal Chat→AuthProxy registration) is on the roadmap and will not break browser ICE semantics. Until then, treat the responder as public infrastructure.

Configuration

"Stun": {
// Master switch. Setting to false disables both the responder and diagnostics endpoints.
"Enabled": true,

// Override the auto-resolved web port if your deployment terminates HTTPS on a different
// socket from the listen port (for example behind an edge NAT or reverse proxy).
"WebPortOverride": null
}

Restart of AuthProxy is required for changes to take effect — the responder is a singleton service.

Out of scope

  • TURN allocation (Allocate / CreatePermission / ChannelBind). Use coturn for relay flows.
  • STUN over TLS / DTLS.
  • Long-term credentials (USERNAME / MESSAGE-INTEGRITY with HMAC).
  • IPv6 dual binding when IPv4 binding fails.