I’m building a WebSocket-based microservice architecture using Spring Cloud Gateway and STOMP WebSockets.
Users log in through the frontend, and the backend sets:

  • access_token (HttpOnly, Secure, SameSite)

  • refresh_token (HttpOnly)

The frontend cannot read these cookies (as expected).
Everything works fine for normal HTTP requests β€” the HttpOnly cookies are automatically sent with each request to the gateway.

🚨 Problem

When I try to connect to the WebSocket endpoint:

const client = new Client({
 webSocketFactory: () => new WebSocket('ws://localhost:8090/ws-chat'),
 connectHeaders: {
 Cookie: `access_token=${TOKEN}` // <-- this is impossible in real browser
 }
});

Cookie is always null on the backend gateway:

@Override
public GatewayFilter apply(Config config) {
 return (exchange, chain) -> {
 System.out.println(exchange.getRequest().getCookies());
 // Result: {}
 };
}

Because the frontend cannot access HttpOnly cookies, I cannot attach the access token to the WebSocket handshake request.

So inside my gateway filter this fails:
String accessToken = request.getCookies().getFirst("access_token").getValue();

// access_token is null => NullPointerException

❓ Question

How do real apps like WhatsApp, Telegram, etc. handle WebSocket authentication when the token is stored in HttpOnly cookies and the frontend cannot read it?

Specifically:

  1. How can I securely authenticate WebSocket connections through the gateway?

  2. How can I pass authentication data during CONNECT handshake when browser JS cannot read cookies?

  3. Is there a pattern (e.g., temporary WS token, session handshake, etc.) that I should implement?