joewalnes/websocketd · error
same origin policy violated
Error message
same origin policy violated
What it means
checkOrigin enforces cross-origin WebSocket security. When the request's Origin header parses to a host/port different from the server's own host/port (and no --origin list is consulted first to save it), the upgrade is rejected with this error and gorilla/websocket answers the handshake with HTTP 403. It exists to prevent other websites' JavaScript from driving your websocketd scripts with the user's credentials.
Source
Thrown at libwebsocketd/http.go:379
}
log.Associate("origin", originParsed.String())
if config.SameOrigin || config.AllowOrigins != nil {
originServer, originPort, err := tellHostPort(originParsed.Host, originParsed.Scheme == "https")
if err != nil {
log.Access("session", "Origin hostname parsing error: %s", err)
return err
}
if config.SameOrigin {
localServer, localPort, err := tellHostPort(req.Host, req.TLS != nil)
if err != nil {
log.Access("session", "Request hostname parsing error: %s", err)
return err
}
if originServer != localServer || originPort != localPort {
log.Access("session", "Same origin policy mismatch")
return fmt.Errorf("same origin policy violated")
}
}
if config.AllowOrigins != nil {
if !matchOrigin(originServer, originPort, originParsed.Scheme, config.AllowOrigins) {
log.Access("session", "Origin is not listed in allowed list")
return fmt.Errorf("origin list matches were not found")
}
}
}
return nil
}
// matchOrigin checks if the given origin server/port/scheme matches any entry
// in the allowed origins list. Extracted for testability.
//
// Port semantics (issue #473): an entry with an explicit port matches that
// port only. A portless entry matches only the scheme's default port (80 for
// http, 443 for https — both, if the entry carries no scheme). AppendingView on GitHub (pinned to 7a8683dc7f)
Solutions
- Add the frontend's exact origin to --origin, e.g. --origin=http://app.example.com:8080 (repeatable or comma-separated per matchOrigin semantics).
- Serve the client page from the same host and port as websocketd so the same-origin check passes automatically.
- If behind a proxy, ensure the Host header forwarded to websocketd matches the origin your page uses, or disable the proxy's host rewriting.
- For non-browser clients (curl, wscat) the Origin header is irrelevant or absent — this only blocks browser handshakes that send a mismatching Origin.
Example fix
// before websocketd --port=8080 ./chat.sh // after websocketd --port=8080 --origin=http://localhost:3000 ./chat.sh
Defensive patterns
Strategy: validation
Validate before calling
const url = new URL('ws://localhost:8080/echo');
if (url.host !== location.host) throw new Error(`origin ${url.host} != server ${location.host}; pass --origin=${location.origin}`); Try / catch
try {
const ws = new WebSocket('ws://localhost:8080/echo');
ws.onerror = () => console.error('handshake rejected (likely 403 origin mismatch)');
} catch (e) { console.error('ws setup failed', e); } Prevention
- Serve the client page from the same host:port as websocketd during development.
- Explicitly pass --origin for every origin allowed to connect; don't rely on same-origin defaults in prod.
- After changing ports or scheme (http→https), update the origin list and test the handshake.
- Check the server's 'Same origin policy mismatch' access log line to learn the exact origin to allow.
When it happens
Trigger: A browser page served from http://app.example.com:8080 opens a WebSocket to ws://otherhost:9999/ while the server runs without --origin; or the page uses localhost vs 127.0.0.1 mismatch; or a reverse proxy rewrites the Host so the server compares it against a different origin than the browser sent.
Common situations: Frontend on a different port than the dev server; serving the HTML from a CDN/static host while websocketd runs elsewhere; forgetting the --origin flag when splitting frontend and backend; tests (TestCheckOrigin) exercising mismatched host/port pairs.
Related errors
- origin list matches were not found
- script not found
- too many forks active
- --anyorigin means 'accept any origin' and cannot be combined
- --maxframesize must not be negative; use 0 for unlimited
AI-assisted analysis of joewalnes/websocketd@7a8683dc7f (2026-09-03).
Data as JSON: /api/errors/182795634ba8d884.
Report an issue: GitHub.