Login and Password in dashboard (localhost:1880/ui)?!

Hi,
i wish to put a login and password in my interface dashboard (localhost:1880/ui) like in (localhost:1880) how i can do that please?!

Thank you for your help.

2 Likes
1 Like

Thank you , but i think that this solution it's made for code dashboard(localhost:1880) and not for my interface dashboard (localhost:1880/ui)
Thank you for your help.

you should move either the editor - see the httpAdminRoot entry in settings.js,
or the http path - httpRoot. The dashboard is off {httpRoot}/ui so securing that uses the method for httpRoot

Thank you for your response, but i don't understand, I have to uncomment this lines?!!
node-red
thank you for your help.

Hello Imadouino,

For the UI edit on settings.js to set an user & passw for HTTPS , I think this is what you wanted.

Uncomment and edit as follows:

// To password protect the node-defined HTTP endpoints (httpNodeRoot), or
// the static content (httpStatic), the following properties can be used.
// The pass field is a bcrypt hash of the password.
// See http://nodered.org/docs/security.html#generating-the-password-hash
httpNodeAuth: {user:"xxxx",pass:"xxxx"
httpStaticAuth: {user:"xxx",pass:"xxxxx`

Regards

6 Likes

Thank you it's work !!! !

Question about securing the ui dashboard with httpNodeAuth as indicated (but not explained well) here:
https://nodered.org/docs/security#http-node-security

Do I understand correctly that turning on httpNodeAuth will add a user/pw login screen not only for accessing the ui dashboard, but also for any POST APIs ("http in" nodes) my flows are relying on?
i.e. external apps need to be able to login to my Node-Red instance in order to send POST messages to my node-red application?

If this is correct, is there any way to protect the ui dashboard without hindering my incoming POST APIs?

2 Likes

No - they currently both use the same express path. (from the Core of Node-RED point of view the dashboard is just another http endpoint)
It is something we want to get to at some point - but isn't short term.

OK thanks for clarifying.

So if I use the ui dashboard as a control panel of any kind i'd need to add some sort of authentication at least. Let me know if you have any best-practices or common mistakes... I'm thinking of just adding a password that needs to be typed in or something like that as a minimal work-around.

I've seen some examples where the dashboard shows a numeric pin pad -- once you enter the correct code, it redirects you to other dashboard "pages". It's definitely a low-tech way to provide some basic "security", but it sounds like it would work for your situation.

image

[{"id":"7d92dedf.5c1b3","type":"ui_template","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","name":"Key 1","order":1,"width":"2","height":"2","format":"<md-button class=\"vibrate filled touched bigfont rounded\" style=\"background-color:#333333\" ng-click=\"send({payload: '1' })\"> \n<svg width=\"105px\" height=\"105px\" version=\"1.1\" viewBox=\"0 0 200 200\">\n <g id=\"Key-1\">\n  <rect fill=\"#4D4D4D\" width=\"200\" height=\"200\" rx=\"12\" ry=\"12\"/>\n  <path fill=\"none\" stroke=\"#B3B3B3\" stroke-width=\"7.99957\" d=\"M6 194c-1,-1 -2,-3 -2,-6l0 -176c0,-4 4,-8 8,-8l176 0c2,0 4,1 6,2\"/>\n  <path fill=\"none\" stroke=\"#1A1A1A\" stroke-width=\"7.99957\" d=\"M194 6c1,1 2,3 2,6l0 176c0,4 -4,8 -8,8l-176 0c-2,0 -4,-1 -6,-2\"/>\n  <text x=\"59\" y=\"153\" style=\"fill: #E6E6E6; font-weight: normal; font-size: 150px; font-family: Arial;\">1</text>\n </g>\n</svg>\n</md-button>\n","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":110,"y":380,"wires":[["49d71834.096548"]]},{"id":"39cd572c.1e4138","type":"ui_template","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","name":"Key 6","order":6,"width":"2","height":"2","format":"<md-button class=\"vibrate filled touched bigfont rounded\" style=\"background-color:#333333\" ng-click=\"send({payload: '6'})\"> \n<svg width=\"105px\" height=\"105px\" version=\"1.1\" viewBox=\"0 0 200 200\">\n <g id=\"Key-6\">\n  <rect fill=\"#4D4D4D\" width=\"200\" height=\"200\" rx=\"12\" ry=\"12\"/>\n  <path fill=\"none\" stroke=\"#B3B3B3\" stroke-width=\"7.99957\" d=\"M6 194c-1,-1 -2,-3 -2,-6l0 -176c0,-4 4,-8 8,-8l176 0c2,0 4,1 6,2\"/>\n  <path fill=\"none\" stroke=\"#1A1A1A\" stroke-width=\"7.99957\" d=\"M194 6c1,1 2,3 2,6l0 176c0,4 -4,8 -8,8l-176 0c-2,0 -4,-1 -6,-2\"/>\n  <text x=\"59\" y=\"153\" style=\"fill: #E6E6E6; font-weight: normal; font-size: 150px; font-family: Arial;\">6</text>\n </g>\n</svg>\n</md-button>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":390,"y":420,"wires":[["49d71834.096548"]]},{"id":"d9986fc8.49167","type":"ui_template","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","name":"Key 3","order":3,"width":"2","height":"2","format":"<md-button class=\"vibrate filled touched bigfont rounded\" style=\"background-color:#333333\" ng-click=\"send({payload: '3' })\"> \n<svg width=\"105px\" height=\"105px\" version=\"1.1\" viewBox=\"0 0 200 200\">\n <g id=\"Key-3\">\n  <rect fill=\"#4D4D4D\" width=\"200\" height=\"200\" rx=\"12\" ry=\"12\"/>\n  <path fill=\"none\" stroke=\"#B3B3B3\" stroke-width=\"7.99957\" d=\"M6 194c-1,-1 -2,-3 -2,-6l0 -176c0,-4 4,-8 8,-8l176 0c2,0 4,1 6,2\"/>\n  <path fill=\"none\" stroke=\"#1A1A1A\" stroke-width=\"7.99957\" d=\"M194 6c1,1 2,3 2,6l0 176c0,4 -4,8 -8,8l-176 0c-2,0 -4,-1 -6,-2\"/>\n  <text x=\"59\" y=\"153\" style=\"fill: #E6E6E6; font-weight: normal; font-size: 150px; font-family: Arial;\">3</text>\n </g>\n</svg>\n</md-button>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":390,"y":380,"wires":[["49d71834.096548"]]},{"id":"513389a4.589638","type":"ui_template","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","name":"Key 4","order":4,"width":"2","height":"2","format":"<md-button class=\"vibrate filled touched bigfont rounded\" style=\"background-color:#333333\" ng-click=\"send({payload: '4'})\"> \n<svg width=\"105px\" height=\"105px\" version=\"1.1\" viewBox=\"0 0 200 200\">\n <g id=\"Key-4\">\n  <rect fill=\"#4D4D4D\" width=\"200\" height=\"200\" rx=\"12\" ry=\"12\"/>\n  <path fill=\"none\" stroke=\"#B3B3B3\" stroke-width=\"7.99957\" d=\"M6 194c-1,-1 -2,-3 -2,-6l0 -176c0,-4 4,-8 8,-8l176 0c2,0 4,1 6,2\"/>\n  <path fill=\"none\" stroke=\"#1A1A1A\" stroke-width=\"7.99957\" d=\"M194 6c1,1 2,3 2,6l0 176c0,4 -4,8 -8,8l-176 0c-2,0 -4,-1 -6,-2\"/>\n  <text x=\"59\" y=\"153\" style=\"fill: #E6E6E6; font-weight: normal; font-size: 150px; font-family: Arial;\">4</text>\n </g>\n</svg>\n</md-button>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":110,"y":420,"wires":[["49d71834.096548"]]},{"id":"2a464b8b.558314","type":"ui_template","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","name":"Key 5","order":5,"width":"2","height":"2","format":"<md-button class=\"vibrate filled touched bigfont rounded\" style=\"background-color:#333333\" ng-click=\"send({payload: '5'})\"> \n<svg width=\"105px\" height=\"105px\" version=\"1.1\" viewBox=\"0 0 200 200\">\n <g id=\"Key-5\">\n  <rect fill=\"#4D4D4D\" width=\"200\" height=\"200\" rx=\"12\" ry=\"12\"/>\n  <path fill=\"none\" stroke=\"#B3B3B3\" stroke-width=\"7.99957\" d=\"M6 194c-1,-1 -2,-3 -2,-6l0 -176c0,-4 4,-8 8,-8l176 0c2,0 4,1 6,2\"/>\n  <path fill=\"none\" stroke=\"#1A1A1A\" stroke-width=\"7.99957\" d=\"M194 6c1,1 2,3 2,6l0 176c0,4 -4,8 -8,8l-176 0c-2,0 -4,-1 -6,-2\"/>\n  <text x=\"59\" y=\"153\" style=\"fill: #E6E6E6; font-weight: normal; font-size: 150px; font-family: Arial;\">5</text>\n </g>\n</svg>\n</md-button>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":250,"y":420,"wires":[["49d71834.096548"]]},{"id":"2de88430.b7864c","type":"ui_template","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","name":"Key 7","order":7,"width":"2","height":"2","format":"<md-button class=\"vibrate filled touched bigfont rounded\" style=\"background-color:#333333\" ng-click=\"send({payload: '7'})\"> \n<svg width=\"105px\" height=\"105px\" version=\"1.1\" viewBox=\"0 0 200 200\">\n <g id=\"Key-7\">\n  <rect fill=\"#4D4D4D\" width=\"200\" height=\"200\" rx=\"12\" ry=\"12\"/>\n  <path fill=\"none\" stroke=\"#B3B3B3\" stroke-width=\"7.99957\" d=\"M6 194c-1,-1 -2,-3 -2,-6l0 -176c0,-4 4,-8 8,-8l176 0c2,0 4,1 6,2\"/>\n  <path fill=\"none\" stroke=\"#1A1A1A\" stroke-width=\"7.99957\" d=\"M194 6c1,1 2,3 2,6l0 176c0,4 -4,8 -8,8l-176 0c-2,0 -4,-1 -6,-2\"/>\n  <text x=\"59\" y=\"153\" style=\"fill: #E6E6E6; font-weight: normal; font-size: 150px; font-family: Arial;\">7</text>\n </g>\n</svg>\n</md-button>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":110,"y":460,"wires":[["49d71834.096548"]]},{"id":"1f5853d8.36dbdc","type":"ui_template","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","name":"Key 2","order":2,"width":"2","height":"2","format":"<md-button class=\"vibrate filled touched bigfont rounded\" style=\"background-color:#333333\" ng-click=\"send({payload: '2' })\"> \n<svg width=\"105px\" height=\"105px\" version=\"1.1\" viewBox=\"0 0 200 200\">\n <g id=\"Key-2\">\n  <rect fill=\"#4D4D4D\" width=\"200\" height=\"200\" rx=\"12\" ry=\"12\"/>\n  <path fill=\"none\" stroke=\"#B3B3B3\" stroke-width=\"7.99957\" d=\"M6 194c-1,-1 -2,-3 -2,-6l0 -176c0,-4 4,-8 8,-8l176 0c2,0 4,1 6,2\"/>\n  <path fill=\"none\" stroke=\"#1A1A1A\" stroke-width=\"7.99957\" d=\"M194 6c1,1 2,3 2,6l0 176c0,4 -4,8 -8,8l-176 0c-2,0 -4,-1 -6,-2\"/>\n  <text x=\"59\" y=\"153\" style=\"fill: #E6E6E6; font-weight: normal; font-size: 150px; font-family: Arial;\">2</text>\n </g>\n</svg>\n</md-button>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":250,"y":380,"wires":[["49d71834.096548"]]},{"id":"76ea846e.bfbe4c","type":"ui_template","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","name":"Key 8","order":8,"width":"2","height":"2","format":"<md-button class=\"vibrate filled touched bigfont rounded\" style=\"background-color:#333333\" ng-click=\"send({payload: '8'})\"> \n<svg width=\"105px\" height=\"105px\" version=\"1.1\" viewBox=\"0 0 200 200\">\n <g id=\"Key-8\">\n  <rect fill=\"#4D4D4D\" width=\"200\" height=\"200\" rx=\"12\" ry=\"12\"/>\n  <path fill=\"none\" stroke=\"#B3B3B3\" stroke-width=\"7.99957\" d=\"M6 194c-1,-1 -2,-3 -2,-6l0 -176c0,-4 4,-8 8,-8l176 0c2,0 4,1 6,2\"/>\n  <path fill=\"none\" stroke=\"#1A1A1A\" stroke-width=\"7.99957\" d=\"M194 6c1,1 2,3 2,6l0 176c0,4 -4,8 -8,8l-176 0c-2,0 -4,-1 -6,-2\"/>\n  <text x=\"59\" y=\"153\" style=\"fill: #E6E6E6; font-weight: normal; font-size: 150px; font-family: Arial;\">8</text>\n </g>\n</svg>\n</md-button>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":250,"y":460,"wires":[["49d71834.096548"]]},{"id":"b92fbf33.e21cc","type":"ui_template","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","name":"Key 9","order":9,"width":"2","height":"2","format":"<md-button class=\"vibrate filled touched bigfont rounded\" style=\"background-color:#333333\" ng-click=\"send({payload: '9'})\"> \n<svg width=\"105px\" height=\"105px\" version=\"1.1\" viewBox=\"0 0 200 200\">\n <g id=\"Key-9\">\n  <rect fill=\"#4D4D4D\" width=\"200\" height=\"200\" rx=\"12\" ry=\"12\"/>\n  <path fill=\"none\" stroke=\"#B3B3B3\" stroke-width=\"7.99957\" d=\"M6 194c-1,-1 -2,-3 -2,-6l0 -176c0,-4 4,-8 8,-8l176 0c2,0 4,1 6,2\"/>\n  <path fill=\"none\" stroke=\"#1A1A1A\" stroke-width=\"7.99957\" d=\"M194 6c1,1 2,3 2,6l0 176c0,4 -4,8 -8,8l-176 0c-2,0 -4,-1 -6,-2\"/>\n  <text x=\"59\" y=\"153\" style=\"fill: #E6E6E6; font-weight: normal; font-size: 150px; font-family: Arial;\">9</text>\n </g>\n</svg>\n</md-button>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":390,"y":460,"wires":[["49d71834.096548"]]},{"id":"e167bcb5.de23","type":"ui_template","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","name":"Key *","order":10,"width":"2","height":"2","format":"<md-button class=\"vibrate filled touched bigfont rounded\" style=\"background-color:#333333\" ng-click=\"send({payload: '*'})\"> \n<svg width=\"105px\" height=\"105px\" version=\"1.1\" viewBox=\"0 0 200 200\">\n <g id=\"Key-Reset\">\n  <rect fill=\"#4D4D4D\" width=\"200\" height=\"200\" rx=\"12\" ry=\"12\">\n    <title>Reset</title>\n  </rect>\n  <path fill=\"none\" stroke=\"#B3B3B3\" stroke-width=\"7.99957\" d=\"M6 194c-1,-1 -2,-3 -2,-6l0 -176c0,-4 4,-8 8,-8l176 0c2,0 4,1 6,2\"/>\n  <path fill=\"none\" stroke=\"#1A1A1A\" stroke-width=\"7.99957\" d=\"M194 6c1,1 2,3 2,6l0 176c0,4 -4,8 -8,8l-176 0c-2,0 -4,-1 -6,-2\"/>\n  <text x=\"50\" y=\"250\" style=\"fill: #E6E6E6; font-weight: normal; font-size: 250px; font-family: Arial;\">*</text>\n </g>\n</svg>\n</md-button>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":110,"y":500,"wires":[["49d71834.096548"]]},{"id":"54f95096.51461","type":"ui_template","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","name":"Key 0","order":11,"width":"2","height":"2","format":"<md-button class=\"vibrate filled touched bigfont rounded\" style=\"background-color:#333333\" ng-click=\"send({payload: '0'})\"> \n<svg width=\"105px\" height=\"105px\" version=\"1.1\" viewBox=\"0 0 200 200\">\n <g id=\"Key-0\">\n  <rect fill=\"#4D4D4D\" width=\"200\" height=\"200\" rx=\"12\" ry=\"12\"/>\n  <path fill=\"none\" stroke=\"#B3B3B3\" stroke-width=\"7.99957\" d=\"M6 194c-1,-1 -2,-3 -2,-6l0 -176c0,-4 4,-8 8,-8l176 0c2,0 4,1 6,2\"/>\n  <path fill=\"none\" stroke=\"#1A1A1A\" stroke-width=\"7.99957\" d=\"M194 6c1,1 2,3 2,6l0 176c0,4 -4,8 -8,8l-176 0c-2,0 -4,-1 -6,-2\"/>\n  <text x=\"59\" y=\"153\" style=\"fill: #E6E6E6; font-weight: normal; font-size: 150px; font-family: Arial;\">0</text>\n </g>\n</svg>\n</md-button>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":250,"y":500,"wires":[["49d71834.096548"]]},{"id":"3569b378.05d7ac","type":"ui_template","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","name":"Key #","order":12,"width":"2","height":"2","format":"<md-button class=\"vibrate filled touched bigfont rounded\" style=\"background-color:#333333\" ng-click=\"send({payload: '#'})\"> \n<svg width=\"105px\" height=\"105px\" version=\"1.1\" viewBox=\"0 0 200 200\">\n <g id=\"Key-Enter\">\n  <rect fill=\"#4D4D4D\" width=\"200\" height=\"200\" rx=\"12\" ry=\"12\">\n    <title>Enter</title>\n  </rect>\n  <path fill=\"none\" stroke=\"#B3B3B3\" stroke-width=\"7.99957\" d=\"M6 194c-1,-1 -2,-3 -2,-6l0 -176c0,-4 4,-8 8,-8l176 0c2,0 4,1 6,2\"/>\n  <path fill=\"none\" stroke=\"#1A1A1A\" stroke-width=\"7.99957\" d=\"M194 6c1,1 2,3 2,6l0 176c0,4 -4,8 -8,8l-176 0c-2,0 -4,-1 -6,-2\"/>\n  <text x=\"59\" y=\"153\" style=\"fill: #E6E6E6; font-weight: normal; font-size: 150px; font-family: Arial;\">#</text>\n </g>\n</svg>\n</md-button>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":390,"y":500,"wires":[["49d71834.096548"]]},{"id":"f99d83cc.b54df","type":"ui_text","z":"c54ebe65.60eaa","group":"d4851ecc.b4b53","order":13,"width":0,"height":0,"name":"keys pressed","label":"Number:","format":"{{msg.payload}}","layout":"row-spread","x":610,"y":380,"wires":[]},{"id":"49d71834.096548","type":"function","z":"c54ebe65.60eaa","name":"code entry","func":"var key = msg.payload;\nvar out = context.get(\"code\") || \"\";\n\nif (key === \"#\") {\n    key = \"\"; // send code\n}\nelse if (key === \"*\") {\n    key = \"\"; // reset code\n    out = \"\";\n}\nelse if (!isNaN(+key)) {\n    out += key; // append key\n}\ncontext.set(\"code\", key ? out : undefined);\n\n// output #1: keys entered\n// output #2: completed code\nmsg.payload = out;\nreturn [\n    key ? msg : {payload: \"\"},\n    out ? msg : null\n];","outputs":2,"noerr":0,"x":570,"y":440,"wires":[["f99d83cc.b54df"],["abbb2a40.b43368"]],"outputLabels":["last key number","completed code"]},{"id":"abbb2a40.b43368","type":"debug","z":"c54ebe65.60eaa","name":"code entered","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","x":610,"y":500,"wires":[]},{"id":"d4851ecc.b4b53","type":"ui_group","z":"","name":"Keypad","tab":"f71dee08.232e9","order":5,"disp":true,"width":"6"},{"id":"f71dee08.232e9","type":"ui_tab","z":"","name":"Button Panel","icon":"dashboard"}]

In one of my posts, I mentioned using a global variable to hold some "code entered ok" flag, and checking that is set whenever a new dashboard page is opened. The ui_control node can be used to send any unauthorized user back to the pin pad.

4 Likes

Steve,
the keypad doesn't look so good in macOS in any of the browsers:

maybe need to adjust borders, gap of the overall dashboard, etc...

Hi there, I know it is old topic but did anyone was able to secure /ui with form login method, so that login page shows in browser and not like pop up asking for credentials?

1 Like

Has anyone seen a way of doing this yet?
I definitely want to be able to password protect my dashboard without having to worry about authentication for webhooks and the like.

There are lots of ways to provide some security.

The main thing to remember is that the browser itself can never really be the source of security, you have to validate on the server.

Then you have to remember that your security is only ever as good as the security of the server itself. So you must keep that safe.

Finally, there is not much point in providing a login if you don't also secure the connection between the browser and the server - for that you need to configure TLS and use HTTPS (and the matching WSS for websockets which happens automatically).

2 Likes

Change the dashboard url path to some long random hash, seems like an easy "fix"

1 Like

not really... it can be easily found

Hi, I have "the same problem". I want to secure dashboard (so I have to configure httpNodeAuth) but I want a http in node to have free access from outside.
Is there any kind of authentification in GET/POST request to a http in node?
ÂżHeaders?
Thanks.
NOTE: I am using SSL from outside and redirecting it to NodeRed in localhost with NGINX. NodeRed is configured as http.

Hi,
You can add a header with Authorization property like this

headers: {
            'Authorization': 'Basic .....=='
        }

where the 'Basic .....==' string includes the base64 encoded value of your basic auth credentials.

1 Like