How to create users with different permission levels in Nun-db

We have recently taken an important step towards pushing Nun-db into mainstream use cases. Now, assigning multiple users to a single database and defining different permission levels for each is possible. In this tutorial, we will walk you through the process of creating two different users, one to be used by the front end of your application and one to be used by the back end.

Let’s consider the following use case: you are developing a system, and you need the server to push updates to the client. For example, if the backend is waiting for a payment confirmation webhook, and once it is processed, stored, and fine, the frontend must, as soon as possible, show the user that the process is finished. In this scenario, it is very important that the front end MUST not be able to change the values, but it must watch and read the values. To support that, we must restrict the frontend user to only read keys and allow the server to read and write all keys. That is what this tutorial will show.

First, we must have a Nun-db process running and a database created. Let’s start by running Nun-db with docker on your local computer.

Starting Nun-db locally

docker run --env NUN_USER=user-name --env NUN_PWD=user-pwd --env NUN_DBS_DIR="/data" --mount type=bind,source="/tmp",target=/data -it --rm -p 3013:3013 -p 3012:3012 -p 3014:3014 --name nun-test mateusfreira/nun-db

Nice, now you have Nun-db running on your local computer. Time to create your first database.

Lets use the same docker container to execute the next commands.

Creating your first database

  1. Connect docker container to execute commands
docker exec -it nun-test  /bin/sh

All the following commands will now be executed inside this docker.

  1. Create the database
 nun-db -u user-name -p user-pwd create-db -d sample -t sample-pwd
  1. Test your database credentials. Note that all commands from this point will use the use prefix to get into the sample db context
nun-db -u user-name -p user-pwd exec "use sample sample-pwd; keys"
# Response "valid auth\n;empty;keys ,$$token,$connections\n"
  1. Excellent, now create the user for that database.

In this case, we will create two users, a server and a client. Where the server can write to all keys and the client can read all keys but only write to keys prefixed with client-*.

4.1 Create user server

nun-db -u user-name -p user-pwd exec "use sample sample-pwd; create-user server server-pwd;"

4.1.1 Checking the user presence

nun-db -u user-name -p user-pwd exec "use sample sample-pwd; keys;"
# Response "valid auth\n;empty;keys ,$$token,$$user_server,$connections\n"

The existence of the key $$user_server proves the user was created

4.2 Create the user client

nun-db -u user-name -p user-pwd exec "use sample sample-pwd; create-user client client-pwd;"

4.1.1 Checking the client user existence

nun-db -u user-name -p user-pwd exec "use sample sample-pwd; keys;"
Response "valid auth\n;empty;keys ,$$token,$$user_client,$$user_server,$connections\n"

The presence of the key $$user_client proves the command worked.

Setting user permissions

Now, our users are created, and we need to set up permissions for them. In this use case, we want the server to be able to do all operations in all keys and the client to real all but only write in the keys prefixed as client-*. Let’s start by creating the server permissions.

Server access all keys

This command will set the permission to the user server to all keys * to (r) read, (w) write, and (x) delete.

nun-db -u user-name -p user-pwd exec "use sample sample-pwd; set-permissions server rwx *;"

Clean read all keys, write only client-* keys

Here you will need 2 sets of permissions, one to give the read all r * and read, write and delete client- keys rwx client-* when applying more than one rule for a single user you separate them by |. Remember, resetting the permissions to a user will overwrite the old permissions and not complement them; be careful.

nun-db -u user-name -p user-pwd exec "use sample sample-pwd; set-permissions client r *|rwx client-*;"

Verifying client permissions

To verify a users permission all you need to do is to get the key value $$permission_${user_name_here} e.g:

nun-db -u user-name -p user-pwd exec "use sample sample-pwd; get \$\$permission_\$client"
# Response "valid auth\n;empty;value r *|rwx client-*\n"

Nice, that means our client permissions are set correctly. Lets now write a small Node.js program to use this credentials.

Creating the sample nodejs app to test permissions

Now the next commands must be executed out of the docker container, back to your computer.

mkdir app
cd app
npm init
npm install nun-db
touch index.js
# edit index.js

Testing client permissions

const NunDb = require('nun-db');
async function run() {
	const nunDb = new NunDb({ url: "ws://localhost:3012", db: "sample", user: "client", token: "client-pwd"});
	const keys  = await nunDb.keys();
	const value = await nunDb.get("name");
	//console.log({ keys, value });
	try {
		await nunDb.set("name", "Jose");
		console.error('This should not happen!!');
		process.exit(1);
	} catch (e) {
		console.log(e.message);
		console.log(`This is correct`);
		process.exit(0);
	}
}
run();
  • When you run that code you shall see the 2 messages print permission denied and This is correct, that means all your settings are correct until here.

So now lets do the same with the server keys

Now note that the server can perform both operations without throwing any exception.

const NunDb = require('nun-db');
async function run() {
	const nunDb = new NunDb({ url: "ws://localhost:3012", db: "sample", user: "server", token: "server-pwd"});
	const keys  = await nunDb.keys();
	const value = await nunDb.get("name");
	console.log({ keys, value });
	try {
		await nunDb.set("name", "Jose");
		console.log(`This is correct`);
	} catch (e) {
		console.error('This should not happen!!');
		process.exit(1);
	}
}
run();

Running that you will see the message This is correct means your code worked as expected.

Conclusion

In this tutorial, we created two users with very different permissions, 1 the client that must real all keys but only write to a small set of keys and one server that can real and write data to all keys. This is a very common use case where you may want your users to read and watch values updated, but the frontend can only write to a small set of keys (or maybe none).

There are several use cases for this that we will explore in the future HOW Tos posts.

Written on September 17, 2023