Backend-UI Authentication

Hallo,

Happy New Year to All! :slight_smile:
I want to write a Postman websocket queries to access the OpenEMS Backend, similar to how io.openems.backend.b2bwebsocket works. Similar to Externe Applikation Anbindung

I looked at the Developer tools in the web browser and tried the requests being sent from the UI. If the URL it is sending data to is wss://Backend_Address/BackendAccess I see responses like:

{"jsonrpc":"2.0","method":"authenticateWithToken","params":{"token":"LONG_TOKEN"},"id":"b61662d7-9dc7-4cb9-8448-4ec06a3951c2"}

If I attach the token in my RPC request and send it to the URL from Postman, then I get a response. But this token is linked to the user and password I use to access the OpenEMS UI. Is there someway to generate the token for the backend access without being linked to a particular user?
Also, how/where is the login Token generated? In the UI code, I see it set in websocket.ts but I do not know how to generate the token. I also see the token used by the User class of Metadata. Is that relevant?

Any advice and guidance is very welcome.

Best

Hi @dsen,

I do not have experience with Postman Websocket queries. There have been some issues with the Backend-to-Backend-Websocket implementation, that have been fixed in:

The PR also contains a demo application that shows how to use the API → https://github.com/OpenEMS/openems/blob/50de0bf79a10cc3c59999b2791a599345b9b0c65/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/B2bWebsocketTest.java

Regards,
Stefan

Hi @stefan.feilmeier,

Thank you for the PR. I was also following the code in the Edge application, in io.openems.edge.controller.api.backend, but still a bit confused about how the websocket communication is established with regards to authenticateWithToken.
The scenario is as follows:
The Edge instance and connected devices are running within a company network, the Backend and UI instances are available via the internet, with the edge is sending data to the backend. I can’t modify the the Backend and UI code.
I need to query and send data from the Edge devices for further processing and control. Due to the network situation, I wanted to communicate with the Backend instance, similar to the UI. Since I also need to data for further processing, I can’t use the UI as is.

Is this the correct place to be looking? Alternatively, is it possible to send data and control messages to the UI in the same JSON-RPC format?

Thank you :slight_smile:

Warm regards

Hi @dsen ,

this use-case is explicitely what the “Backend-to-Backend Api” is designed for.

As there can be multiple Edges connected to a backend, you need to wrap your JSONRPC-Request in an EdgeRpc-Request. Backend will then forward it to the Edge:

https://openems.github.io/openems.io/openems/latest/component-communication/index.html#_edge_rpc

Full JSONRPC requests often wrap the content multiple times and look like this:

{
  "method": "edgeRpc",
  "params": {
    "edgeId": "edge0",
    "payload":{
      "method": "componentJsonApi",
      "params": {
        "componentId": "onewire0",
        "payload": {
          "method": "getDevices",
          "params": {}
        }
      }
    }
  }
}

(taken from OneWire-Bridge documentation)

1 Like

@stefan.feilmeier Thank you! This will clear up my problem, I think. The format in my message was wrong.

Warm regards

Hallo @stefan.feilmeier ,

Does the “authenticateWithPassword” method work for Backend as well? I see it used in the schema to Authenticate UI to Edge using password.

I am sending the following to the Backend:

{"jsonrpc":"2.0",
"method":"authenticateWithPassword",
"params":{"password":"MY_EdgePass", "username":"MyEdge_User", 'id':"Backend_ID"},
"id":"ID_here"
}

and get the error:

{
    "jsonrpc": "2.0",
    "id": "ID_here",
    "error": {
        "code": 1,
        "message": "Cannot invoke \"io.openems.backend.common.metadata.User.getId()\" because \"user\" is null",
        "data": [
            "Cannot invoke \"io.openems.backend.common.metadata.User.getId()\" because \"user\" is null"
        ]
    }
}

When i send the same request with the field ‘user’ instead of username, I get authentication failed:

{
    "jsonrpc": "2.0",
    "id": "ID_here",
    "error": {
        "code": 1003,
        "message": "Authentication failed",
        "data": []
    }
}

However when I use my token, the process is successful.

{"jsonrpc":"2.0",
"method":"authenticateWithToken",
"params":{"token":"Token_here"},
"id":"ID_here",
}

I’d like to use the user-password method of authentication. I also tried using the B2BWebSocketTest code but I get Code [-1] Reason [Connection refused: connect].

Any advice would welcome.
Thanks!

Authorization to Backend-to-Backend-Websocket is done via http-headers. Example:

Map<String, String> httpHeaders = new HashMap<>();
var auth = new String(
		Base64.getEncoder().encode((B2bWebsocketTest.USERNAME + ":" + B2bWebsocketTest.PASSWORD).getBytes()),
		StandardCharsets.UTF_8);
httpHeaders.put("Authorization", "Basic " + auth);
var client = new TestClient(new URI(B2bWebsocketTest.URI), httpHeaders);
client.startBlocking();

(see openems/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/B2bWebsocketTest.java at 50de0bf79a10cc3c59999b2791a599345b9b0c65 · OpenEMS/openems · GitHub)

As the Websocket stays open afterwards, you do not need to authenticate again.

I also tried using the B2BWebSocketTest code but I get Code [-1] Reason [Connection refused: connect].

Die you follow this advice?

**
 * This Test demonstrates the usage of the OpenEMS Backend-to-Backend API
 * interface. To start the tests make sure to start OpenEMS Backend and activate
 * the B2bWebsocket component via Apache Felix. Afterwards run this App via
 * main().
 */

(see openems/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/B2bWebsocketTest.java at 50de0bf79a10cc3c59999b2791a599345b9b0c65 · OpenEMS/openems · GitHub)

Regards,
Stefan

Hallo @stefan.feilmeier ,

Thank you for clearing it up so quickly.
I would have to check if the OpenEMS B2bWebsocket component is active. The Backend isn’t in my control. I modified the B2bWebsocketTest.URI to point to the Backend location.
As for the authentication, I am sending the credentials I use to login to the custom UI. Could it be possible that a different set of credentials is needed to login to the associated Backend?

Warm Regards,

Please follow the advice and start the Backend-to-Backend API locally. This way you can test if the problem is on your side or on the side of the Backend provider.

If the problem is at the Backend, you’d have to get in touch with the provider. Maybe he is not running the latest version or does not have the Backend-to-Backend API running.

@stefan.feilmeier I would have to ask the provider. Temporarily, I am using the token for authentication.

I had doubts about the frequency of data received from the backend. Currently I think there is a new update every 15 seconds (atleast that’s how often I am receiving a message from the socket)?
Is it possible to change that frequency or maybe prevent a method from sending an update? Specifically, the method “edgeRpc” keeps sending in data.

Thank you and warm regards

If there is new data for subscribed channels, you should receive updates every two seconds by default. See → openems/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/SubscribedEdgesChannelsWorker.java at develop · OpenEMS/openems · GitHub