NKeys

NKeys are a new, highly secure public-key signature system based on Ed25519.

With NKeys the server can verify identities without ever storing or ever seeing private keys. The authentication system works by requiring a connecting client to provide its public key and digitally sign a challenge with its private key. The server generates a random challenge with every connection request, making it immune to playback attacks. The generated signature is validated against the provided public key, thus proving the identity of the client. If the public key is known to the server, authentication succeeds.

NKey is an excellent replacement for token authentication because a connecting client will have to prove it controls the private key for the authorized public key.

To generate nkeys, you’ll need the nk tool.

Generating NKeys and Configuring the Server

To generate a User NKEY:

  1. > nk -gen user -pubout
  2. SUACSSL3UAHUDXKFSNVUZRF5UHPMWZ6BFDTJ7M6USDXIEDNPPQYYYCU3VY
  3. UDXU4RCSJNZOIQHZNWXHXORDPRTGNJAHAHFRGZNEEJCPQTT2M7NLCNF4

The first output line starts with the letter S for Seed. The second letter, U stands for User. Seeds are private keys; you should treat them as secrets and guard them with care.

The second line starts with the letter U for User and is a public key which can be safely shared.

To use nkey authentication, add a user, and set the nkey property to the public key of the user you want to authenticate:

  1. authorization: {
  2. users: [
  3. { nkey: UDXU4RCSJNZOIQHZNWXHXORDPRTGNJAHAHFRGZNEEJCPQTT2M7NLCNF4 }
  4. ]
  5. }

Note that the user section sets the nkey property (user/password/token properties are not needed). Add permission sections as required.

Client Configuration

Now that you have a user nkey, let’s configure a client to use it for authentication. As an example, here are the connect options for the node client:

  1. const NATS = require('nats');
  2. const nkeys = require('ts-nkeys');
  3. const nkey_seed = SUACSSL3UAHUDXKFSNVUZRF5UHPMWZ6BFDTJ7M6USDXIEDNPPQYYYCU3VY’;
  4. const nc = NATS.connect({
  5. port: PORT,
  6. nkey: 'UDXU4RCSJNZOIQHZNWXHXORDPRTGNJAHAHFRGZNEEJCPQTT2M7NLCNF4',
  7. sigCB: function (nonce) {
  8. // client loads seed safely from a file
  9. // or some constant like `nkey_seed` defined in
  10. // the program
  11. const sk = nkeys.fromSeed(Buffer.from(nkey_seed));
  12. return sk.sign(nonce);
  13. }
  14. });
  15. ...

The client provides a function that it uses to parse the seed (the private key) and sign the connection challenge.