Markus
Markus

Reputation: 1563

Vertx SockJs Eventbus Authentication

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?

Upvotes: 2

Views: 2682

Answers (3)

Norbert Sch&#246;pke
Norbert Sch&#246;pke

Reputation: 486

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).

Upvotes: 1

Shasha
Shasha

Reputation: 669

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));

Upvotes: 0

berserkk
berserkk

Reputation: 1007

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.

Upvotes: 7

Related Questions