NATS.io Programmatic NKeys and JWTs with Node

Bo Motlagh
United Effects™
Published in
5 min readJul 31, 2022

--

I’ve spent the last few weeks exploring NATS.io and JetStream and I’m very impressed. I’m actually a little confused how I didn’t know about JetStream sooner… it’s a great achievement and the folks working on it should be very proud. In fact, its forcing us to rethink some technology decisions at United Effects… but we’ll get into that another time.

NATS is built on Go, which is just awesome. That said, my go-to language to learn a new tech interface from is Node. It’s just faster for me personally and I’m much more experienced with it. It was great to see that most of the documentation provided by NATS also has node client and configuration examples, or is simple enough to easily derive a Node version from the provided Go examples.

One concept that I did find a little challenging to understand was programmatically managing Accounts (a NATS tenant to isolate data) and Users in a configured instance or cluster. The Nats By Example site got me started with some ideas, but lacked an E2E example. I eventually figured it out (or something that works anyway) and I figured that I’d document my approach based on their example in Node, just in case there’s anyone else like me out there. Here’s how I got it working:

Step 1

First thing you need to do is get NATS working locally. There are a few options for install available, but my preference was to launch it using docker. Here’s an approach that worked well for me:

  • I created a directory to manage a docker mounted volume
  • I created a docker-compose.yml that allowed me to pull the image, expose the ports, mount the local directory as a volume for configurations, and send command options like “-js” or “-c /yourconfig.conf” to the image.
  • I created a local directory for NATS to manage JWTs
  • I used a very simple nats.conf file in the locally mounted volume to kick it off

Structure

>local-directory/
>>jwt/
>>nats.conf
>>docker-compose.yml

Docker-compose

nats.conf

NOTE: This will launch NATS, but we haven’t initialized Operator and System accounts yet so its not usable. Notice that I’ve enabled JetStream.

Step 2

We need to initiate a usable configuration file that gives us an Operator and System Account. In a multi-tenant setup like we are building, a system account is needed to interact with $SYS subjects which control things like Accounts in NATS. An operator account is the highest level of authority and among other things, must sign all JWTs representing the new accounts we create (BTW — if you’re an expert on this stuff, feel free to comment with corrections!).

The easiest way to do this I found is to use the NSC tool and simply run the “nsc init” command. You can install and read about the NSC tool here: https://github.com/nats-io/nsc

Run the “nsc init” command and follow the instructions to initialize an operator, an account, and a user.

Export the resulting configuration using:

Delete the original “nats.conf” and rename this new one to replace the original. It will look something like this:

Step 3

You’ll need the nKey seeds. I’ll save the explainer on nKeys since the team at Synadia and NATS do a great job, but you can check out the details here:

You can retrieve the public keys and seeds from the operator, account, and user you just created using the following commands (the entity name is optionally randomly generated):

IMPORTANT: SEEDS ARE SECRETS. Do not share them. The seeds below are for a local test environment on my machine and will never be available outside of that context.

Hold on to these.

Step 4

Grab the System Account User JWT that was generated by NSC. You should be able to find this in the location where NSC is storing its credentials files. There’s probably a simpler way, but that’s how I did it. You can inspect the claims of your JWT just by using jwt.io as one approach.

Step 5

Spin up the docker-compose and let’s programatically add an account and create a user! Just type “docker-compose up” in the local directory we created in step 1.

In any other directory, initiate a node project and install the following packages via yarn or npm:

  • yarn add nats-jwt
  • yarn add nkeys.js

Gist here

https://gist.github.com/theBoEffect/ccdfe18cff5ec7876c784a3c7a45d307

Results from the node above

IMPORTANT: If you’ve configured NATS to use JWTs as Bearer tokens, they should not be shared and as a best practice, when generated, they should have an expiration. Otherwise they can be considered a public document. (thank you Alberto Ricart for the correction)

Conclusion

You’ll know this worked because there will be no authorization errors and if you look in your /jwt directory, you’ll see a new Account JWT file.

Compulsory Plug

At United Effects we regularly explore new technologies like NATS as we try to make our Core EOS platform the best possible solution for product integration and market acceleration.

Follow us on Twitter, LinkedIn and Medium and if you need help with anything related to Core EOS, do not hesitate to reach out to help@unitedeffects.com.

--

--