Spring 4.x token-based WebSocket SockJS fallback authentication
<p>Getting Spring Boot 1.4 + Spring 4.x + Spring Security 4.x WebSocket authentication to work with stateless token-based authentication seems to be an adventure!</p>

<p>So far, as I understand it, SockJS is not able to set the <code>Authentication</code> header with the token because browser's do not expose that API to Javascript (see <a href="https://github.com/sockjs/sockjs-client/issues/196" rel="nofollow">https://github.com/sockjs/sockjs-client/issues/196</a>). I have worked around that by setting the authentication token in a query parameter as suggested on the above issue, and then using a Spring <code>HandshakeHandler</code> with <code>determineUser()</code> to map the query parameter to a User entity. Ugly and less secure, but at least it works for WebSockets.</p>

<p>However, when SockJS falls back to another mechanism e.g. XHR streaming, the same mechanism no longer works. A <code>HandshakeInterceptor</code> has access to the request and can obtain the authentication from the query param, but <strong><code>determineUser</code> on the <code>HandshakeHandler</code> is never called for non-WebSocket handshakes</strong>.</p>

<p>The closest I have gotten so far is to bypass the built-in  connection-level Spring machinery to determine the authentication. Instead, I set the authentication token at the message-level by setting it in the Stomp headers on the client side e.g.:</p>



<pre><code>stompClient.send("/wherever", {token: 'token'}, ...);
</code></pre>

<p>and extract it on the server-side with a channel interceptor:</p>



<pre><code>configureClientInboundChannel(ChannelRegistration registration) {
  registration.setInterceptors(new ChannelInterceptorAdapter() {
     Message&lt;*&gt; preSend(Message&lt;*&gt; message,  MessageChannel channel) {
      StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
      // not documented anywhere but necessary otherwise NPE in StompSubProtocolHandler!
      accessor.setLeaveMutable(true);
      List tokenList = accessor.getNativeHeader("token");
      if(tokenList == null || tokenList.size &lt; 1) {
        return message;
      }
      Principal yourAuth = [...];
      return MessageBuilder.createMessage(message.payload, accessor.messageHeaders)
    }
  })
</code></pre>

<p>Now Spring injects the <code>Principal</code> into any controller methods that require it, BUT the <code>user</code> <strong>is still not saved to the websocket session</strong>, so messages still cannot be sent to a particular user.</p>

<p>How do I get Spring to "see" the authentication extracted from the query parameter?</p>