← Node-RED Admin Login on a Touchscreen HMI (TouchBerry Pi)
Node-RED Admin Login on a Touchscreen HMI (TouchBerry Pi) — full example
Protect Node-RED dashboard settings with an admin password, on-screen keyboard and session timeout on a TouchBerry Pi touchscreen HMI panel.
Complete, runnable program for the TouchBerry Pi (admin-auth-virtual-keyboard-timeout.js): wiring header, requirements and integration notes included.
Download the full project pack — freeThis example + the related ones + bill of materials
Read-only preview.
/*
* COMPLETE EXAMPLE — Administrator authentication with virtual keyboard and timeout
*
* Hardware: TouchBerry Pi (Raspberry Pi + Industrial Shields PLC, touch screen)
* Based on: industrial mixing project (Node-RED touch HMI)
*
* Requirements:
* - Node-RED with @flowfuse/node-red-dashboard (Dashboard 2.0 / UI v2)
* - No physical keyboard: the password is entered with an on-screen keyboard
*
* Flow wiring (left to right):
*
* [ui-button "Settings"] ──> [function 1: checkSession] ──┬─(valid session)──> [ui-control: go to page /settings]
* └─(expired)────────> [ui-template: virtual keyboard popup]
*
* [ui-template keyboard] ──> [function 2: validatePassword] ──┬─(ok)────> [ui-control: go to /settings] + [ui-notification "Access granted"]
* └─(wrong)─> [ui-notification "Incorrect password"]
*
* [inject "on deploy" once=true] ──> [function 3: initCredentials]
*
* Node configuration:
* - ui-button "Settings": sends no relevant payload, it only triggers the check.
* - ui-template: form with input type=password and on-screen keyboard
* (on Raspberry Pi OS you can use 'matchbox-keyboard' or your own HTML keyboard);
* pressing OK emits msg.input with the typed text and msg.payload = true.
* - The two output paths are split with a switch node on msg.auth.
*/
// ============================================================
// function 3: initCredentials (runs once on deploy)
// ------------------------------------------------------------
// Stores the password and the session timeout in the global context.
// In production, load them from a file or environment variable,
// never in plain text inside the exported flow.
// ============================================================
global.set("adminPwd", env.get("ADMIN_PWD") || "CAMBIAR_PASSWORD");
global.set("adminLoginTimeout", 10 * 60 * 1000); // 10 minutes in ms
global.set("lastAdminLoginDate", null); // nobody logged in at startup
return msg;
// ============================================================
// function 2: validatePassword (receives msg from the virtual keyboard)
// ------------------------------------------------------------
// msg.payload == true -> the operator pressed OK
// msg.input -> text entered on the on-screen keyboard
// Output 1: access granted / Output 2: rejected
// ============================================================
if (msg.payload) {
if (msg.input == global.get("adminPwd")) {
// Access granted: record the instant for the session timeout
global.set("lastAdminLoginDate", new Date());
msg.auth = true;
msg.payload = "Administrator access granted";
return [msg, null];
}
// Incorrect password: do not reveal hints in the message
msg.auth = false;
msg.payload = "Incorrect password";
return [null, msg];
}
return [null, null]; // popup cancelled: do nothing
// ============================================================
// function 1: checkSession (runs when "Settings" is pressed)
// ------------------------------------------------------------
// If the last login is more recent than adminLoginTimeout,
// the user goes straight in without being asked for the password again.
// Output 1: valid session / Output 2: ask for password
// ============================================================
const last = global.get("lastAdminLoginDate");
const timeout = global.get("adminLoginTimeout") || 600000;
if (last && (new Date() - new Date(last)) < timeout) {
// Session still valid: renew it and let the user through
global.set("lastAdminLoginDate", new Date());
msg.auth = true;
return [msg, null];
}
// Session expired (or never started): open the keyboard popup
global.set("lastAdminLoginDate", null);
msg.auth = false;
return [null, msg];
// ============================================================
// (Optional) function 4: manualLogout
// ------------------------------------------------------------
// Connected to a "Log out" ui-button inside /settings:
// invalidates the session immediately without waiting for the timeout.
// ============================================================
global.set("lastAdminLoginDate", null);
msg.payload = "Administrator session closed";
return msg;
Download the full project pack — freeThis example + the related ones + bill of materials