'How to use JWT with WebSocketChannel in Flutter

I have an existing Websocket Channel which needs authenticate user by his JWT in order to send/receive messages using this socket connection. The problem is - I don't know how to send my access token in message body when establishing connection. The official documentation says:

"If the url contains user information this will be passed as basic authentication when setting up the connection."

But in my case JWT is passed in a message like this:

{"method":"auth","accessToken":"${MY_TOKEN}"}

I tried to connect by passing JWT in headers or use sink after connection is established, but when I send a new message, it only calls onDone callback and closes connection.

  final _channel = IOWebSocketChannel.connect('${WEB_SOCKET_URL}');

...

  void initState() {
    _channel.stream.listen((message) {
      print('message');
    }, onError: (error, StackTrace stackTrace) {
      print('error');
    }, onDone: () {
      print('done');
    });

    _channel.sink.add({
      "method": "auth",
      "accessToken": "${MY_TOKEN}"
    });
}

I expect connection to be established and then I can use it to send/received messages but it's only closes when I try to use "sink.add()" method.



Solution 1:[1]

You are trying to send an object on the socket I think it is not happy with that. The server may not be able trop properly handle the error of receiving something other than a json string and closes the connection.

Try this to send a json string:

    var message = {
      "method": "auth",
      "accessToken": "${MY_TOKEN}"
    };

    _channel.sink.add(jsonEncode(message));

Solution 2:[2]

Give a try to this method. This is easy as mentioned in https://api.flutter.dev/flutter/dart-io/WebSocket/connect.html

  final WebSocketChannel channel =
  IOWebSocketChannel.connect("ws://<socketurl>/ws/",headers: {
    'Content-type': 'application/json',
   'Accept': 'application/json',
   'Authorization': 'Bearer $yourtoken'
  });

Solution 3:[3]

You may pass it in the URL:

WebSocketChannel.connect("ws://localhost:8080/api/foo/ws?authorization=eyJhbGciOiJIUzI1...")

Using IOWebSocketChannel as suggested throws a platform error if used with flutter web, whereas WebSocketChannel automatically determines the proper platform.

Traditionally it was considered poor practice to have credentials in query params because URLs can get stored in places such as logs for proxies, browser history, etc. However, neither of those concerns apply to websockets (a browser won't keep history of the connections made by a page), and proxies do not have access to the URL when there is a TLS tunnel. This concern arose when non-TLS interactions were the default.

source

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Muldec
Solution 2 REVANTH N D
Solution 3