Background
When implementing real-time bidirectional communication for applications like chat systems, WebSocket connections require proper authentication. While HTTP APIs typically use Authorization headers for token validation, WebSocket connections present a challenge since custom headers cannot be directly set during the upgrade process.
Two common approacehs exist for transmitting authentication tokens during WebSocket handshake:
- Appending token as URL query parameter
- Using WebSocket subprotocol to carry token data
The subprotocol method transmits the token through the Sec-WebSocket-Protocol header, providing better security than URL exposure.
Implementation and Connection Issues
Client-Side Code
const authToken = sessionStorage.get("authToken");
const socketConnection = new WebSocket(
`ws://${window.location.host}/websocket/chat`,
[authToken]
);
Server-Side Token Validation
Java backend requires a custom handshake interceptor to process the token before WebSocket connection establishment:
@Component
public class AuthHandshakeInterceptor implements HandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler handler,
Map<string object=""> sessionAttributes) {
String protocolToken = request.getHeaders()
.getFirst("Sec-WebSocket-Protocol");
TokenPayload tokenData = TokenValidator.verify(protocolToken);
if (tokenData == null) {
return false; // Reject connection
}
sessionAttributes.put("AUTH_USER",
new AuthenticatedUser(
tokenData.getUserId(),
tokenData.getUsername()
));
return true; // Accept connection
}
@Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler handler,
Exception error) {
// Post-handshake operations
}
}</string>
The interceptor validates the token during the handshake phase and stores user information in session attributes for later use during WebSocket message handling.