I have an issue running the flowfuse dashboard behind cloudflare zero-trust, using google to authenticate.
When the token expires the dashboard is initially unaffected. It seems that the existing websocket connection continues ok even though the token has expired. That is ok. However, if I switch pages in the dashboard then bits of the dashboard do not appear and in the browser (edge) console I see stuff like
Access to script at 'https://me.cloudflareaccess.com/cdn-cgi/access/login/nodered.mydomain.uk?kid=...&redirect_url=%2Fresources%2F%40colinl%2Fnode-red-dashboard-2-ui-gauge-classic%2Fui-gauge-classic.umd.js' (redirected from 'https://nodered.mydomain.uk/resources/@colinl/node-red-dashboard-2-ui-gauge-classic/ui-gauge-classic.umd.js') from origin 'https://nodered.mydomain.uk'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
GET https://me.cloudflareaccess.com/cdn-cgi/access/login/nodered.mydomain.uk?kid=...&redirect_url=%2Fresources%2F%40colinl%2Fnode-red-dashboard-2-ui-gauge-classic%2Fui-gauge-classic.umd.js net::ERR_FAILED 200 (OK)
TypeError: Failed to fetch dynamically imported module: https://nodered.mydomain.uk/resources/@colinl/node-red-dashboard-2-ui-gauge-classic/ui-gauge-classic.umd.js
Is there a solution to this?
Refreshing the page takes me to the login page, but it would be much better if this happened automatically.
Does this always happen when you switch pages, or only after token expiration?
Do you want your page to go to login automatically and unsolicitedly once the token expires?
I've highlighted this as an issue many times. It isn't specifically a Node-RED issue but rather stems from the fact that websocket connections do not allow custom headers and therefore the server cannot verify if a session token is still valid.
There are ways to work around this, the easiest being to include any authentication/authorisation token in EVERY message that passes between client and server. This is why UIBUILDER has a set of hooks that allow processing like this to be added.
I think this is basically saying that the browser will not allow access to that "foreign" resource origin.
You will need to adjust Node-RED's CORS settings to allow access.
I'm afraid I can never remember how to do this and always have to look up the correct CORS header.
Only if the token has expired. Also I suspect that it may only happen the first time that page is visited. Hopefully it is not fetching the contrib node every time the page is opened.
I suppose that would be the ideal, though personally I don't have strong feelings about it. I suppose that if I can find where the resources are loaded then forcing a page reload when the error occurs would be ok.
I have done such an implementation at a live project, where the flow goes back automatically to login after a timeout (in case of token) or configurable time with no user activity. It also forces going through the login and blocks direct access to the page.
Do you want me to share?
Unfortunately this was wishful thinking on my part. I have moved on from the particular case described above to the more serious one which arises if the auth session expires and then an attempt is made to open the websocket connection. Currently this fails and the code assumes that the server is unavailable and repeatedly retries the connection, which accomplishes nothing. The correct action is to force a page reload.
I have documented this in the issue below, but have not so far found a solution. If anyone who knows anything about such things could have a look at that and maybe offer some ideas that would be great.
Preferably continue discussions on the issue page rather than here please.
When a socket.io connection attempt starts (or a raw ws: connection for that matter), the initial connection is over http(s). This initial connection is the only place that custom http headers are supported (well, for socket.io, the fallback long-polling is http(s) so that supports it too but that is an aside). So what should happen is that the socket.io connection should have the same header processing as the main ExpressJS handler in terms of authentication and proxy related headers.
Sounds like this isn't happening. So I would suggest that this is probably a bug.
What tells you that? I am not saying you are wrong, I am just trying to understand what is going on, we are outside my knowledge base here. The reason the connection attempt fails is that the initial https attempts to redirect to the login page (which is a cloudflare domain) and fails with a CORS error.
Hard won experience! Went through all of this (several times over the years) with UIBUILDER.
UIBUILDER has several places where you can add in custom Socket.IO message processing so that you can hook in authentication and authorisation logic. These hooks for example which you can configure in the uibuilder section of your settings.js file:
It has taken me a LOT of time and angst trying to understand the inner workings of websockets in general and Socket.IO specifically.
Well, it is perfectly possible that I've misunderstood. I suppose that what you are really covering here is what the client does rather than the server? I do get a bit wrapped up with the server logic!
At the very least though, some additional logic is likely to be needed for when a socket.io (re)connection attempt fails.
I don't know how this is managed in the D2 client libraries, I only know how I do it. And truthfully, my reconnection logic - though it works - isn't ideal. Indeed, I currently have a slightly related issue to yours in developing Markweb (single-node website creator in uibuilder). I want to reload the page after a client has disconnected and then reconnected - as happens a lot when your browser or its host goes into sleep mode and then back out. In the uibuilder client library, I expose custom events for this happening but the logic isn't quite right to be able to capture only a reconnection and not the initial series of connections that happen normally (first connection is over http(s), then you may get several long polling connections and finally an "upgrade" connection - which you can see has a 101 response code in the network tab of your browser dev tools).
This issue is, in fact, the focus of tomorrow.
Anyway, sorry for the side-track. Bottom line, you probably need a way to respond to socket.io connection errors in the browser, not sure if they are exposed in D2.