fix: NCS-122 authenticate WebSocket connections via first-message auth #73

Merged
Janis merged 2 commits from fix/NCS-122-ws-token-auth into main 2026-06-17 10:42:54 +02:00
Owner

Replace header-based auth (not possible with browser WebSocket API) with a
first-message auth protocol: client sends {"type":"auth","token":""}
as the first text frame; server validates and proceeds or closes the connection.

Both GameWebSocketResource and UserWebSocketResource now hold incoming
connections in a pendingAuth set until the auth frame arrives, preventing
any game or event messages from being processed before identity is established.

Also removes the broken Bearer-prefix handling that caused header-based auth
to silently fail even for non-browser clients.

Note on authentication approach

The token is not sent via the HTTP Authorization header. The browser's native WebSocket API does not allow setting custom HTTP headers during the
handshake — this is a hard browser specification constraint, not a framework limitation.

Instead this PR implements first-message auth: the client sends {"type":"auth","token":""} as the first text frame immediately after the
connection opens. The server validates the token before processing any further messages and closes the connection if the token is missing or
invalid.

This moves the token out of the URL query parameter (visible in server logs and browser history) and into an encrypted WebSocket frame, which is
the standard approach used by production WebSocket APIs (Slack, Discord, etc.) for the same reason.

The alternatives that would put the token in an actual HTTP header are:

  • Cookie — store the JWT as Secure; SameSite=Strict cookie on login; browser sends it automatically with the upgrade request
  • Sec-WebSocket-Protocol trick — pass the token as a subprotocol value; non-standard and visible in tooling as a protocol string

If cookie-based auth is preferred in the future, that would be a separate ticket covering the login flow.

Replace header-based auth (not possible with browser WebSocket API) with a first-message auth protocol: client sends {"type":"auth","token":"<JWT>"} as the first text frame; server validates and proceeds or closes the connection. Both GameWebSocketResource and UserWebSocketResource now hold incoming connections in a pendingAuth set until the auth frame arrives, preventing any game or event messages from being processed before identity is established. Also removes the broken Bearer-prefix handling that caused header-based auth to silently fail even for non-browser clients. Note on authentication approach The token is not sent via the HTTP Authorization header. The browser's native WebSocket API does not allow setting custom HTTP headers during the handshake — this is a hard browser specification constraint, not a framework limitation. Instead this PR implements first-message auth: the client sends {"type":"auth","token":"<JWT>"} as the first text frame immediately after the connection opens. The server validates the token before processing any further messages and closes the connection if the token is missing or invalid. This moves the token out of the URL query parameter (visible in server logs and browser history) and into an encrypted WebSocket frame, which is the standard approach used by production WebSocket APIs (Slack, Discord, etc.) for the same reason. The alternatives that would put the token in an actual HTTP header are: - Cookie — store the JWT as Secure; SameSite=Strict cookie on login; browser sends it automatically with the upgrade request - Sec-WebSocket-Protocol trick — pass the token as a subprotocol value; non-standard and visible in tooling as a protocol string If cookie-based auth is preferred in the future, that would be a separate ticket covering the login flow.
lq64 added 1 commit 2026-06-17 09:46:23 +02:00
fix(ncs-122): authenticate WebSocket connections via first-message auth
Build & Test (NowChessSystems) TeamCity build failed
a75a3cc421
Replace header-based auth (not possible with browser WebSocket API) with a
first-message auth protocol: client sends {"type":"auth","token":"<JWT>"}
as the first text frame; server validates and proceeds or closes the connection.

Both GameWebSocketResource and UserWebSocketResource now hold incoming
connections in a pendingAuth set until the auth frame arrives, preventing
any game or event messages from being processed before identity is established.

Also removes the broken Bearer-prefix handling that caused header-based auth
to silently fail even for non-browser clients.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
lq64 force-pushed fix/NCS-122-ws-token-auth from 9386f1bb19 to a75a3cc421 2026-06-17 09:46:23 +02:00 Compare
lq64 added 1 commit 2026-06-17 10:01:12 +02:00
style(ncs-122): fix scalafmt alignment in GameWebSocketResource
Build & Test (NowChessSystems) TeamCity build finished
e8ff9cd6e6
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Janis merged commit 343e2bdd10 into main 2026-06-17 10:42:54 +02:00
Janis deleted branch fix/NCS-122-ws-token-auth 2026-06-17 10:42:55 +02:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: NowChess/NowChessSystems#73