node-red-dashboard
node-red-dashboard copied to clipboard
Infinite loop when express-openid-connect middleware is used
Current Behavior
When a custom middleware based on "express-openid-connect" is used during the time of the first session everything operates normally but once it expires and new one needs to be established an infinite loop is created. This is because "callback" route critical for this middleware is served by PWA's service worker from its cache instead of the middleware itself which needs to return a session in form of a cookie. A simple solution for this particular case is provided by below patch, more generic one could consist of configuration variable for excluded routes for example.
--- a/ui/src/sw.js
+++ b/ui/src/sw.js
@@ -22,6 +22,8 @@ if (import.meta.env.DEV) {
// this permits the request to be handled by the server which will do a redirect as required
const configPath = self.location.pathname.split('/')[1]
denylist.push(new RegExp(`/${configPath}/[^?]*/(\\?.*)*$`))
+ // don't precache the callback route which is handled by express-openid-connect middleware
+ denylist.push(new RegExp(`/${configPath}/callback\\?`))
}
// to allow work offline for allowed routes only
Expected Behavior
No response
Steps To Reproduce
- Configure custom OIDC middleware in settings.js, example configuration used with Hashicorp Vault:
dashboard: {
middleware: (req, res, next) => {
const issuerBaseURL = "";
const baseURL = "";
const clientID = "";
const clientSecret = "";
const secret = "";
const group ="";
// Workaround for double middleware call bug
if (req.hasOwnProperty("oidc") && req.oidc.isAuthenticated()) return next();
const { auth } = require("express-openid-connect");
const jose = require("jose");
const oidcAuth = auth({
issuerBaseURL: issuerBaseURL,
baseURL: baseURL,
clientID: clientID,
clientSecret: clientSecret,
secret: secret,
authorizationParams: {
response_type: "code",
scope: "openid security"
},
afterCallback: async (request, response, session) => {
const claims = jose.JWT.decode(session.id_token);
if (!(claims.hasOwnProperty("groups") && claims.groups.includes(group)))
return response.sendStatus(401);
return session;
}
});
oidcAuth(req, res, next);
}
}
- Logon to the dashboard
- Close browser tab and delete "appSession" cookie to simulate expired session
- Try to logon to the dashboard again
Environment
- Dashboard version: 1.24.2
- Node-RED version: 4.0.9
- Node.js version: 20.19.0
- npm version:
- Platform/OS: Linux 6.1.0-34-armmp arm LE
- Browser: Edge/Firefox
Have you provided an initial effort estimate for this issue?
I am not a FlowFuse team member