Generating Web API Keys

If you're building a REST API, chances are you're going to need to generate secure random API keys. You may be tempted to use a third-party library but before you do, consider using the crypto package from Node.js. The crypto module can generate random bytes, which can then be used to create your API keys.

The randomBytes() function from the crypto module can be used to generate cryptographically strong pseudo-random data given a size. The size is provided as an argument specifying the number of bytes to generate. Take a look at the following example.

Listing 1

const crypto = require("crypto");

const rand = crypto.randomBytes(20);

console.log(rand);

The result returned from the function is a Buffer object consisting of the generated bytes. If you log the result to the console, you can see the hex value for each byte.

Listing 2

<Buffer 85 c7 b6 96 54 15 75 c8 03 55 9e 2f e6 6f a1 cc b9 24 3e 68>

Joining each hex value together will result in a unique string. This can be done easily by calling the toString('hex') method on the result as shown below.

Listing 3

...
const unique_id = rand.toString("hex")

console.log(unique_id);

// Output similar to 6bba108d4b2212f2c30c71dfa279e1f77cc5c3b2

So now you have a unique id but it looks more like a UID than an API key. There are examples on the web that suggest you should convert the result into a base64 string rather than a hex string but base64 strings are not url friendly as they can contain non alphabet characters and simply replacing these characters with an empty string will give you an uneven string length.

An alternative approach is to pick characters from a predefined set of characters using an index. There are 256 characters that can be represented by a single byte. If you create a string that holds 256 characters, you can use the decimal value for a given byte as the index to lookup a character from the predefined character set. The example code below will hopefully make this clearer.

Listing 4

const crypto = require("crypto");

const rand = crypto.randomBytes(20);

let chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".repeat(5);

let str = '';

for(let i=0; i < rand.length; i++){
    let decimal = rand[i];
    str += chars[decimal];
}

console.log(str);

// Output similar to uUAAw0VabC6YJtbDVyTv

As you can see from the code above, I've created a chars variable that holds more than 256 characters by repeating the string 5 times. The string contains only the characters I want to generate my API keys. The for loop iterates over each byte and the decimal value for the byte is used as an index to select a character from the chars variable. The output now looks more like an API key rather than a UID.

The code above can be made slightly more efficient by not having to create a string with 256 characters. Instead we create a string with only the characters we need and then use the modulo operator to determine the index.

Listing 5

...
let chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

let str = "";

for(let i=0; i < rand.length; i++){
    let index = rand[i] % chars.length;
    str += chars[index];
}

console.log(str);

As you can see it only takes a few lines of code to generate a secure random API key.