2
votes

I'm trying to make a sock.js connection from the frontend to the vertx backend.

my initial try looked like this:

let token = '<the token>';
let data = {'Authorization' : 'Bearer ' + token};
let eb = new EventBus("http://localhost:8080/eventbus");
  eb.onopen = function () {
  eb.registerHandler('notifications', data, (err, msg) =>  {
    // handle the response
  });
}

this doesn't work since I need to send the auth data on EventBus creation, even though the official sock.js documentation states that this is not supported. Obviously now sending new EventBus("http://localhost:9090/eventbus", data) doesn't work either.

https://github.com/sockjs/sockjs-node#authorisation

my backend handler for this:

final BridgeOptions bridgeOptions = new BridgeOptions()
  .addOutboundPermitted(new PermittedOptions().setAddress("notifications"))

final SockJSHandler sockJSHandler = SockJSHandler.create(vertx).bridge(bridgeOptions, event -> {
  event.complete(true);
});

router.route("/eventbus/*").handler(ctx -> {
  String token = ctx.request().getHeader("Authorization"); // null
});
router.route("/eventbus/*").handler(sockJSHandler);

whatever I tried the header field Authroization is always null.

What is the standard way to authenticate the sock.js connection and register to an eventbus request in vertx?

3
Have you checked the Requiring authorisation for messages section of the Vert.x Web doc? - tsegismont
yes, i've read the whole vertx docs - Markus
OK. I asked because your snippet does not look like you use the Vert.x Web authorization functionality. - tsegismont
i already tried the standard JWTAuthHandler approach I do on normal http requests, but the error is the same -> Token not found because I don't know how to send it from the frontend side correctly. the backend works fine - Markus
Have a look at the vertx-examples repo to see the bridge auth in action. Please share a reproducer on GitHub if it still doesn't work. Thanks - tsegismont

3 Answers

7
votes

SockJS uses WebSockets by default. You can't add custom headers (Authorization, etc) using JavaScript WebSocket API. Read this thread for more explanation.

I see 2 ways, how you can add authorization:

  1. Just add token parameter to URL:

    let eb = new EventBus("http://localhost:8080/eventbus?token=" + token);
    

    and here's how you can get it on a server:

    String token = ctx.request().getParam("token");
    
  2. Send authorization message after connecting to the server. It can be some JSON object, which contains token field.

I think, 1st option is enough, however, 2nd one can be harder to implement in terms of Event Bus and SockJS.

1
votes

Since sending Authorization header is not possible, attaching a token query parameter (as described by @berserkk) is the way to go.

However, in some circumstances, it may be undesirable to send your main login token in plain text as a query parameter because it is more opaque than using a header and will end up being logged whoknowswhere. If this raises security concerns for you, an alternative is to use a secondary JWT token just for the web socket stuff.

Create a REST endpoint for generating this JWT, which can of course only be accessed by users authenticated with your primary login token (transmitted via header). The web socket JWT can be configured differently than your login token, e.g. with a shorter timeout, so it's safer to send around as query param of your upgrade request.

Create a separate JwtAuthHandler for the same route you register the SockJS eventbusHandler on. Make sure your auth handler is registered first, so you can check the web socket token against your database (the JWT should be somehow linked to your user in the backend).

0
votes

I think best way to secure a web-socket is using CORS check

Cross Origin Resource Sharing is a safe mechanism for allowing resources to be requested

router.route().handler(CorsHandler.create(your host origin path).allowCredentials(true));

We can add more layer of security also using sockjs :

Allow events for the designated addresses in/out of the event bus bridge

 BridgeOptions opts = new BridgeOptions()
          .addInboundPermitted(new PermittedOptions().setAddressRegex(Constants.INBOUND_REGEXP));