angularspring-bootnginxwebsocket

Spring boot with nginx wss not working from angular


My spring boot websocket(ws) endpoint works fine on localhost with angular (rxstomp).

The prod server use nginx (https) and I can't connect to the ws. The FE and BE are on the same server in docker, on different url.

Nginx conf:

location /ws {

 ...

 proxy_pass http://backend/ws

 ...

}
BE: 

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
                .setAllowedOrigins(frontendUrl);
    }

FE: 

export function rxStompServiceFactory() {
    const rxStomp = new RxStompService();
    rxStomp.configure(myRxStompConfig);
    rxStomp.activate();
    return rxStomp;
}
export const myRxStompConfig: RxStompConfig = {
    brokerURL: 'ws://localhost:8088/ws',
...

Please help

Thanks


Solution

  • First of all, this is our solution and certainly theres a better but it works.

    The problem:

    The BE(backend) and FE(frontend) on the same server with different urls. (fe.app.com and be.app.com) And there's an nginx proxy too.

    The FE can't connect to the BE with websocket.

    So the flow: frontend --> nginx(be.app.com) --> backend

    The main problem was the authorization (Bearer token) when we want to connect with wss to the spring boot app because can't send custom header in wss connect request.

    The solution:

    Save the token to cookies and use this in the backend TokenAuthorizationFilter

    (Here the token cookie name is Authorization)
      if (request.getCookies() != null) {
        for (Cookie c : request.getCookies()) {
          if (Objects.equals(c.getName(), "Authorization")) {
            if (!c.getValue().startsWith("Bearer"))
              authorizationHeader = "Bearer " + c.getValue();
          }
        }
      }
    

    And use this instead of the Authorization param of the requestHeader.

    This is the request header
    String authorizationHeader = request.getHeader("Authorization");
    

    So now we can send the token in the cookies and the backend do the authorization.

    Nice but have an other problem. Important to know how the cookies work! (Share cookie between subdomain and domain)

    The nginx config should forward the cookies too. In this case we called the FE domain from FE (fe.app.com/wss) and in the nginx config set the proxy_pass to the BE websocket location (backendIp:port/ws)

    So the BE get the cookies and use for the authorization.

    I hope it helps. :)