I'm trying to make use of this authentication feature:
So far I'm just checking what the possibilities are and what I've learned are as follows:
httpNodeAuth scenario: cannot be used together with this as the function exported for the dashboard authentication is called after the httpNodeAuth authentication
no httpNodeAuth scenario: when printing from the exported authentication function (implemented in dashboard-auth.js) the req.originalUrl on the console, I see some requests to files and the dashboard root /ui as well but I never see the socketid parameter
First of all, 1) is not a problem but let me know if it's possible.
Concerning 2): my plan is to carry out a passport js local startegy based authentication (user/pw) and use the socketid afterwards as an access token for the user identified. So that's why I'd need to get the socketid from the url. I also tried to get it from the query like req.query.socketid but I always get undefined only.
Do you think this approach to be feasible? If so, how can I get the socketid in the dashboard authentication function?
EDIT: figured out that after the # fragment identifier nothing is sent to the server so the question is rather that if the following is possible?:
Set up a flow (http request node) that gets executed first which sends back the socketid from the client. Then I could check if any user has already been authenticated with that socketid and if not, then force a user/pw logon.
I don't believe that will be all that useful since there are several factors that can cause the sockeid to be reset even from the same browser window/tab. For example, loss of network connectivity (going in/out of standby or moving from wired to wireless) will likely result in a new socketid which is generally not what users would expect.
You can get the socket id using a Dashboard control node as that spits out a msg whenever a new client connects. Just note that a client connection means a browser tab in this case.
You need to pass a token to the client upon connection that the client retains as a cookie or in local storage and that the client returns on each interaction.
And that raises another issue in regard to front-end apps that use websockets for interactions. Once the websocket has "upgraded" to ws(s): rather than http(s): which happens on initial handshake, websockets do not support custom headers which means that you cannot send back a cookie or a JWT authorization header. In turn, this means that you lose control over whether the client connection is still valid.
To get around that problem, you need to add the token to every msg that the client sends back to Node-RED.
This is a problem that I've been struggling with for uibuilder. I believe that I have all the pieces straight now but I need to find enough contiguous time to actually sit down and write up how to do this.
uibuilder already has middleware capability for both its ExpressJS and Socket.IO connectivity so inserting a Passport strategy into both should be easy. But that still wouldn't fix the websocket issue. So I need to document how to do that manually in front-end and back-end code but I also need to think about whether the uibuilderfe front-end library needs any extensions to make inclusion of a security token in the msg send function more transparent (and hence easier to use).
Thanks for the detailed answer! I think I found a workaround. As I don't want to expose the editor to anyone I thought about disabling it in settings.js and using the http API of node red in combination with the custom user authentication (by adminAuth: require("./user-authentication")) providing only read access to the editor (which is anyway disabled). The functions in user-authentication.js seem to get called so if it works out indeed, I'll need to safeguard each http request like action (loading a page, saving something, etc.) and carry out indeed an http request to the NR http API (e.g. GET /settings) to check if the user is indeed logged in and the access token hasn't expired yet. I've just started to work on the logon screen and it seems to be already a challenge as the first thing I do when the logon screen gets loaded is that I send an http request to GET /settings and try to decide if the user is already logged on but somehow I don't get 401 even if I'm not logged on in the editor:(
Do you need Dashboard? If not, uibuilder is probably easier to do this kind of thing with.
Another approach to additional security of your base flows would be to move all of the core logic to a different instance of Node-RED - one that gives no access to end users. Then use comms from that instance to your user instance. That makes certain nobody gets access.