How to get sessionId in STOMP CONNECTED frame using Spring Boot WebSocket?
08:26 03 Nov 2025

I'm working on a Spring Boot application using STOMP over WebSocket. In my UI client app, I receive the CONNECTED frame like this:

["CONNECTED\nversion:1.2\nheart-beat:0,0\n\n\u0000"]

However, I need the sessionId to be included in the CONNECTED frame. Is there a way to include the sessionId in the CONNECTED frame sent to the client? If not directly possible, is there a recommended workaround to pass the session ID to the client in CONNECTED frame? I tried to intercept CONNECTED frame using clientOutbound Channel interceptor, but it is not intercepting CONNECTED frame at all, but if I register a inboundChannel I can intercept all the frames sent from client(CONNECT, SEND, SUBSCRIBE).

WebSocket Config class

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

/**
 * Websocket Configuration class
 */
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    private final CustomHandshakeInterceptor customHandshakeInterceptor;
    
    /**
     * Constructs a {@code WebSocketConfig} with the specified interceptors.
     *
     */
    public WebSocketConfig(CustomHandshakeInterceptor customHandshakeInterceptor) {
        this.customHandshakeInterceptor = customHandshakeInterceptor;
    }

    /**
     * Registers the WebSocket endpoint and configures SockJS support.
     *
     * @param registry the StompEndpointRegistry to register endpoints
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/websocket").addInterceptors(customHandshakeInterceptor).setAllowedOriginPatterns("*").withSockJS();
    }

    /**
     * Configures the message broker for WebSocket communication.
     *
     * @param config the MessageBrokerRegistry to configure message broker
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.setApplicationDestinationPrefixes("/cdsoutput");
        config.enableSimpleBroker("/topic");
    }

    /**
     * Configures the client inbound channel to intercept messages from client to server.
     * This intercepts: CONNECT, SEND, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT
     *
     * @param registration the ChannelRegistration to configure the inbound channel
     */
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(new ManualChannelInterceptor());
    }

    @Override
    public void configureClientOutboundChannel(ChannelRegistration registration) {
        registration.interceptors(new ManualChannelInterceptor());
    }
}

ManualChannelInterceptor class:

import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class ManualChannelInterceptor implements ChannelInterceptor {

    /**
     * Called BEFORE sending a message through the channel.
     * This is where you can intercept, log, or modify messages.
     */
    @Override
    public Message preSend(Message message, MessageChannel channel) {
        final StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);

        if (accessor == null) {
            return message;
        }

        StompCommand command = accessor.getCommand();
        String sessionId = accessor.getSessionId();
        String username = accessor.getUser() != null ? accessor.getUser().getName() : "anonymous";

        // Log every message type
        log.info(">>> preSend: Command={}, SessionId={}, User={}, Destination={}",
                command, sessionId, username, accessor.getDestination());

        if (SimpMessageType.CONNECT_ACK.equals(accessor.getMessageType())) {
            log.info(">>>>>>>>> CONNECT_ACK frame (server → client) - Added session-id header: {}", sessionId);
            accessor.setSessionId(sessionId);
        }

        if (StompCommand.CONNECT.equals(command)) {
            log.info(">>>>>>>>> CONNECT frame (client → server) - SessionId: {}", sessionId);
        }

        if (StompCommand.CONNECTED.equals(command)) {
            log.info(">>>>>>>>> CONNECTED frame (server → client) - Added session-id header: {}", sessionId);
        }

        if (StompCommand.MESSAGE.equals(command)) {
            log.info(">>>>>>>>> MESSAGE frame (broker → client) - Destination: {}", accessor.getDestination());
        }

        if (StompCommand.SEND.equals(command)) {
            log.info(">>>>>>>>> SEND frame (client → server) - From user: {}", username);
        }

        if (StompCommand.SUBSCRIBE.equals(command)) {
            log.info(">>>>>>>>> SUBSCRIBE frame (client → server) - User: {}, Destination: {}", username, accessor.getDestination());
        }

        if (StompCommand.UNSUBSCRIBE.equals(command)) {
            log.info(">>>>>>>>> UNSUBSCRIBE frame (client → server) - User: {}", username);
        }

        if (StompCommand.ACK.equals(command)) {
            log.info(">>>>>>>>> ACK frame - User: {}", username);
        }

        if (StompCommand.DISCONNECT.equals(command)) {
            log.info(">>>>>>>>> DISCONNECT frame (client → server) - User: {}", username);
        }

        return message;
    }
}

Logs are printing for SEND, CONNECT, SUBSCRIBE, basically all frames sent from client, but it is not detecting CONNECTED frame which is sent from server to client.

Please help me to get sessionId in the CONNECTED frame.

websocket spring-websocket stomp sockjs