Skip to content

beryl/transport/origin

Origin and handshake-version checks for WebSocket upgrades.

Pure string-level checks shared by beryl's WebSocket transports. They operate on header and query values, not on server-specific request types; beryl/transport/server applies them to gleam/http requests as part of the shared upgrade pipeline.

pub type OriginPolicy {
SameOrigin
AllowList(List(String))
AllowAll
}

Policy for validating the browser Origin header before a WebSocket upgrade completes.

The Origin check is the primary defense against Cross-Site WebSocket Hijacking (CSWSH): a browser attaches ambient cookies/session credentials to a WebSocket handshake regardless of which site initiated it, so a socket that authenticates from those credentials must reject upgrades that originate from other sites.

Every policy allows a request with no Origin header, with one exception described below. Browsers always send Origin on WebSocket handshakes. An absent header therefore indicates a non-browser client, such as a native app, server, or CLI. The browser same-origin model does not apply to these clients. AllowList is the exception. It requires a matching Origin and rejects an absent header.

SameOrigin

Allow an upgrade only when the request Origin authority (host plus any port, with the scheme stripped) matches the request Host authority. This is the default and rejects cross-site upgrades before the handshake.

A malformed or opaque Origin (e.g. null from a sandboxed iframe, or a value with no host) is rejected. Comparison is over the full host:port authority, so a non-default port must match on both sides.

Behind a reverse proxy, this compares against the Host header that the app receives. Configure the proxy to forward the public Host unchanged, or use AllowList with the public origins instead. Forwarded headers such as X-Forwarded-Host are not trusted, because clients can spoof them.

AllowList(List(String))

Allow an upgrade only when the request Origin header matches one of the listed values exactly (including scheme, host, and any port), such as "https://app.example.com". Requests without an Origin header, or with a non-matching one, are rejected.

AllowAll

Allow every upgrade regardless of Origin. This disables CSWSH protection. Use it only for sockets that do not rely on ambient browser credentials (or that authenticate every message independently).

pub fn allowed(
policy: OriginPolicy,
origin: option.Option(String),
host: option.Option(String)
) -> Bool

Decide whether an upgrade is allowed under the configured origin policy.

origin and host are the request's Origin and Host header values. Use None when a header is absent. SameOrigin and AllowAll admit a request without an Origin header because non-browser clients omit it. AllowList rejects the request because it requires an explicit match.

pub fn version_supported(version: option.Option(String)) -> Bool

Check a client's requested wire protocol version (the ?vsn= query parameter sent by Phoenix clients) before upgrading.

Accept a missing vsn or a value beginning with 2.. Custom-codec clients must omit vsn unless they use that version form. Other values, such as the V1 object framing's vsn=1.0.0, are rejected with 403 Forbidden.