I have following websocket server defined in micronaut:
@ServerWebSocket("/v1/ws/socket")
@Secured(SecurityRule.IS_AUTHENTICATED)
@RequiredArgsConstructor
@Slf4j
public class MyWebSocket {
@OnOpen
public void onOpenSocket(WebSocketSession session) {
String agentRef = session.getUserPrincipal().get().getName();
log.info("opened websocket for: {}", agentRef);
}
@OnClose
public void onClose(CloseReason closeReason) {
log.info("closed websocket websocket with reason: {}", closeReason);
}
@OnMessage
public void onMessage(String message) {
log.info("received message in websocket: {}", message);
}
@OnError
public void onError(Throwable error) {
log.error("an error occured in websocket", error);
}
}
My application has JWT token authentication and in my unit tests I can connect to the socket without a problem like this:
@Inject
@Client("/")
RxWebSocketClient webSocketClient1
@Shared
def bearer = 'example jwt'
def "client can authenticate and connect to the websocket"() {
given:
def request = HttpRequest.GET("/v1/ws/").bearerAuth(bearer)
def MyWebSocketClient client =
webSocketClient1.connect(MyWebSocketClient, request)
.blockingFirst()
expect:
client.session.isOpen()
cleanup:
client.session.close(CloseReason.NORMAL)
}
In the test, client is correctly authenticated and everything works. However I cant authenticate to the websocket in my frontend code, with rxjs socket library. I couldnt find any documentation on how can micronaut handle websocket security in general. Do you have any tips for me?
For anyone interested, after abit of research websockets indeed support authentication - there is an initial HTTP call which results in response switching protocols
and then socket connection is opened.
The idea is to authenticate user on that initial HTTP call - passing your authentication in header as usual. The problem with this however is that either frontend libraries for websockets dont support to pass this header on that http call or the browser doesnt allow it - i am not really frontend guy but that's the gist of it.
I ended up solving it by generating "one time" token that frontend has to generate through rest api, and then pass it to websocket through query. I know that the user is authenticated because the endpoint for generating the token is secured.