This repository contains an example for user management based on Node-RED flows. While it was designed to be immediately usable with the server implemented in node-red-within-express and play well together with the authentication and authorization mechanisms described in node-red-authorization-examples, the example may also be used in other environments.
Nota bene: this work is currently in progress, do not expect it to be finished before end of November 2021
Nota bene: this example uses an extended format for the "User Registry" introduced in "node-red-within-express". If you plan to use it, please update your
registeredUsers.json
file accordingly and take the new user id format into account when accessing the Node-RED editor (e.g.,node-red@mail.de
instead ofnode-red
)
Nota bene: while this example already considers a few legal regulations, no guarantee can be given that these measures are correct and/or complete. It is entirely your responsibility to offer a service which complies with the legal requirements!
Just another small note: if you like this work and plan to use it, consider "starring" this repository (you will find the "Star" button on the top right of this page), so that I know which of my repositories to take most care of.
The example requires the following Node-RED extensions
- node-red-reusable-flows
"Reusable Flows" allow multiply needed flows to be defined once and then invoked from multiple places - node-red-node-email
allows to create and send EMails from Node-RED
Additionally, the example expects the global flow context to contain an object called UserRegistry
which has a format based on the one described in "node-red-within-express" but with a few extensions:
- the object's property names are the email addresses of registered users
(this specification differs from the original one!) - the object's property values are JavaScript objects with the following properties, at least (additional properties may be added at will):
- Roles
is either missing or contains a list of strings with the user's roles. There is no specific format for role names except that a role name must not be longer than 64 characters and must not contain any white space. This example already defines the roleuser-admin
to identify "User Administrators", i.e., users who are allowed to manage the settings of other users - Salt
is a string containing a random "salt" value which is used during PBKDF2 password hash calculation - Hash
is a string containing the actual PBKDF2 hash of the user's password - UUID
is a string containing a version 4 UUID which uniquely identifies a given user even after email address changes (this property has been added to the original specification). If you want to generate UUIDs for already existing users, this online generator might be useful - agreedToDPS
is a boolean indicating that the user has read and agreed to this service's "Data Privacy Statement" and must be set totrue
for an account to get confirmed (this property has been added to the original specification) - agreedToTOS
is a boolean indicating that the user has read and agreed to this service's "Terms of Service" and must be set totrue
for an account to get confirmed (this property has been added to the original specification) - ConfirmationDeadline
if present,ConfirmationDeadline
indicates a pending user id conformation and contains the (UTC) time until when that process has to be completed (or the previously reserved new user id will be released) - ConfirmationToken
contains the token required to complete a pending user id confirmation. Actually, this token should not be saved at all as it could be recomputed from known key data - but then, any server reboot or flow redeployment would break pending user id confirmations (because of a new token key). In order to avoid inconveniences for users, tokens are therefore explicitly saved - PasswordDeadline
if present,PasswordDeadline
indicates a pending password reset and contains the (UTC) time until when that process has to be completed - PasswordToken
contains the token required to complete a pending password reset. Actually, this token should not be saved at all as it could be recomputed from known key data - but then, any server reboot or flow redeployment would break pending password resets (because of a new token key). In order to avoid inconveniences for users, tokens are therefore explicitly saved
- Roles
When used outside "node-red-within-express", the following flows allow such a registry to be loaded from an external JSON file called registeredUsers.json
(or to be created if no such file exists or an existing file can not be loaded) and written back after changes:
Just import these flows, place them on your Node-RED workspace but - if need be - disable the node labelled "at Startup" as the startup sequence is now a different one and will be handled by a different flow. By default, the created user registry contains a single user node-red@mail.de
with the password t0pS3cr3t!
and a single role node-red
(this is exactly the same user who is also included in "node-red-within-express" by default)
A typical user lifecycle looks as follows:
- a new user gets registered
either by him/herself or by an administrator. In this implementation, new users who register themselves only have to specify their email address in order to start a registration. To limit the users who can register, a list of permitted email addresses may be provided to the server - upon registration, an "account confirmation message" is sent by email to the given address
This email contains a link which, when clicked, should navigate the user to a web page (or web application) where the he/she may add additional information (such as his/her real name, f.e.), must define a password for his/her account, must (read and) agree to a "Data Privacy Statement" and to some "Terms of Service" (for legal reasons) and then send that information back to the server in order to confirm the account. If such a confirmation does not happen within a certain period, the registration is automatically cancelled - until then, the given email address is reserved and no other account with the same address may be registered - after successful account confirmation, the user may "log-in" and use the offered service
While this implementation uses the "Header-based Authorization" described in node-red-authorization-examples any of the other methods will work as well - but you will have to modify the flows in this repository accordingly - while logged-in, a user may additionally
- change his/her email address
changing one's email address will actually start a confirmation process similar to that after initial registration. As soon as the new email address is confirmed, the old one will be removed and the new one used from now on for the already existing account. Until then (or if the new address does not get confirmed in time) the old email address continues to work as before - change his/her password
changing one's password requires to specify the old password again for authorization - if that password is fogotten, a "password reset" may be initiated (see below) - change other account details
custom server implementations may need additional user information (such as a user's real name, his/her postal address, credit card details etc.) These details may be changed online as well - except the user's agreement to "Data Privacy Statement" and "Terms of Service", which may only be cleared)
- change his/her email address
- should a user have forgotten his/her password, he/she may start a "password reset" process
As a consequence, a "password reset message" is sent by email to the user's address. This email contains a link which, when clicked, should navigate the user to a web page (or web application) where he/she may define a new password without having to specify the current one - last, but not least, every user may delete his/her account
This action immediately removes the user's account and wipes out any data associated with this user
While "normal" users may only inspect and modify their own accounts, "User Administrators" (i.e., users with the role user-admin
) may also manage the accounts of other people. In particular, they may
- change other user's email addresses
although the new addresses will have to be confirmed in the same way as if the users would have initiated the change themselves - change other user's roles
this function is only available to user administrators - inspect or change other user's account details
any detail may be changed except email addresses, passwords,Salt
andHash
values or the agreement to "Data Privacy Statement" or "Terms of Service" (which may only be cleared) - delete other users
But even "User Administrators" neither have access to other user's passwords nor can they set other user's agreements to the service's "Data Privacy Statement" and "Terms of Service"
Nota bene: the legal documents mentioned above (i.e., "Data Privacy Statement" and "Terms of Service") are not part of this user management implementation but have to be provided separately
Should "Data Privacy Statement" and/or "Terms of Service" change, properties agreedToDPS
and/or agreedToTOS
may be set to false
again. In that case, any new login should immediately redirect the user to a separate web document where he/she may either (read the changed documents and) agree again or delete his/her account. Without such an agreement, the user should no longer be allowed to access the service and logged out immediately.
Administrators also have to agree to these legal statements.
- POST without body
- <user-id> must be a valid email address (max. 64 char.s long) which is neither currently registered nor the new address of an account which is currently being renamed
- the requesting user does not have to authenticate him/herself
- if all conditions are met a registration email will be sent to the given <user-id>
- warning: currently, success of email submission can not be tested - it may be, that an email address is successfully registered which never receives any email
- POST without body
- <user-id> must be the email address of an account which still has to be confirmed (either because it has just been registered or because it is the new address of an account which is currently being renamed)
- the requesting user does not have to authenticate him/herself
- if all conditions are met, another registration email (with the original deadline) will be sent to the given <user-id>
- warning: currently, success of email submission can not be tested - it may be, that an email address is successfully registered which never receives any email
- will be used either to confirm a newly registered account or to confirm the new email address of an existing account
- confirming a newly registered account
- POST with form variables
newPassword
,agreedToDPS
,agreedToTOS
and the confirmationToken
from the submitted confirmation link, at least - <user-id> must be the email address of an account which still has to be confirmed because it has just been registered
- the requesting user does not have to authenticate him/herself
newPassword
must contain a valid password (in this example, with at least 12 char.s and no other constraints)agreedToDPS
must betrue
agreedToTOS
must betrue
Token
must contain a valid confirmation token for the given account- if all conditions are met, a hash for the given
newPassword
,agreedToDPS
andagreedToTOS
will be stored and the account marked as confirmed - the user may now log-in
- POST with form variables
- confirming the new email address of an existing account
- POST with the confirmation
Token
from the submitted confirmation link, at least - <user-id> must be the email address of an account which still has to be confirmed because it is the new address of another account which is currently being renamed
- the requesting user does not have to authenticate him/herself
Token
must contain a valid confirmation token for the given account- if all conditions are met, any settings from the old account are copied to the new one, the new account is marked as confirmed and the old account deleted
- the user may now log-in using the new email address - the old one may no longer be used
- POST with the confirmation
- POST without body
- <user-id> must be the email address of an account which has already been confirmed
- the requesting user does not have to authenticate him/herself
- if this condition is met, a "password reset message" is sent to the given <user-id>
- warning: currently, success of email submission can not be tested - it may be, that a "password reset message" is sent to an address which no longer receives any email
- POST with form variable
newPassword
and theToken
from the submitted password reset link - <user-id> must be the email address of an account which has already been confirmed but is currently in the process of a password reset
- the requesting user does not have to authenticate him/herself
newPassword
must contain a valid password (in this example, with at least 12 char.s and no other constraints)- if all conditions are met, a hash for the given
newPassword
will be stored and the password reset process be marked as complete - warning: only the latest token will be accepted - and this only once
- POST with form variables
agreedToDPS
andagreedToTOS
- <user-id> must be the email address of an account which has already been confirmed
- the requesting user must have authenticated him/herself as the user with the given <user-id>
agreedToDPS
must betrue
agreedToTOS
must betrue
- if all conditions are met,
agreedToDPS
andagreedToTOS
will be stored and the user may continue using the offered service
- POST with form variable
Password
- <user-id> must be the email address of an account which has already been confirmed
Password
must be the current password for this account- if all conditions are met, a "bearer" token with the currently configured lifetime will be generated and returned in an "authorization" header. This token can now be used for further requests to authenticate the logged-in user
- the token expires after a configured time of inactivity but - within its lifetime - it gets refreshed by every request which requires an authentication
- explit authentications are not necessary if "basic HTTP authentication" is used
- POST with form variable
newUserId
- <user-id> must be the email address of an account which has already been confirmed
- the requesting user must have authenticated him/herself either as the user with the given <user-id> or as a user with the role
user-admin
newUserId
must be a valid email address (max. 64 char.s long) which is neither currently registered nor the new address of an account which is currently being renamed- if all conditions are met, a registration email will be sent to
newUserId
- warning: currently, success of email submission can not be tested - it may be, that an email address is successfully registered which never receives any email
- POST with form variables
oldPassword
andnewPassword
- the requesting user must have authenticated him/herself as the user with the given <user-id>
oldPassword
must be the current password for the account with the given <user-id>newPassword
must contain a valid password (in this example, with at least 12 char.s and no other constraints)- if all conditions are met, a hash for the given
newPassword
will be stored in the account and the new password will become active
- POST with form variable
Roles
(containing a space-separated list of permitted user roles) - the requesting user must have authenticated him/herself as a user with the role
user-admin
- if all conditions are met, the given
Roles
will be stored in the account for the given <user-id> and immediately become active
- the requesting user must have authenticated him/herself as the user with the given <user-id> or as a user with the role
user-admin
- if this condition is met, a JSON object with any public details of the account for the given <user-id> is sent back
- POST with arbitrary form variables expect
Password
,Salt
,Hash
,Salt
,ConfirmationDeadline
,PasswordDeadline
,agreedToDPS
,agreedToTOS
andRoles
- the requesting user must have authenticated him/herself as the user with the given <user-id> or as a user with the role
user-admin
- if all conditions are met, the given variables are written to the account for the given <user-id>
- the requesting user must have authenticated him/herself as the user with the given <user-id> or as a user with the role
user-admin
- if this condition is met, the account for the given <user-id> and any associated data is deleted
- for a user with the role
user-admin
it is permitted to delete a non-existing user
The following HTTP endpoints require the requesting user to authenticate as an administrator:
GET /registered-users
responds with a JSON file containing all currently registered users and their settings (see above for their description)PUT /registered-users
updates the list of currently registered users. The request body should therefore contain a JSON specification of all these users and their settings (see above for their description)
GET /permitted-users
responds with a list of all currently permitted users and their intended roles in plain text form. The list contains one user per line, each line starts with the user id (i.e., the user's email address) and (optionally) a blank-separated list of role names for that userPUT /permitted-users
updates the list of all permitted users and their intended roles. The request body should therefore contain a text file with one line per user, starting with the user id (i.e., the user's email address) and (optionally) followed by a blank-separated list of role names for that user
GET /permitted-roles
responds with a list of all currently permitted roles in plain text form - one role name per linePUT /permitted-roles
updates the list of all permitted roles. The request body should therefore contain a text file with a white-space separated list of role names. You may use spaces, tabs, line-feeds and similar white-space characters for separation
This example may be installed as follows:
- import this flow into your Node-RED instance
- configure the "email" node, i.e. enter service details and credentials of an email account you may use for sending email messages
- copy files
registeredUsers.json
,permittedUsers.txt
andpermittedRoles.txt
into your Node-RED working directory - customize these files as needed
As usual, this repository contains a collection of requests which is to be imported into a Postman instance and simplifies testing the feedback mechanism.
Nota bene: you will have to change the user ids mentioned in the Postman Collection in order to access confirmation and password reset emails