In this question Erik needs to generate a secure random token in Node.js. There's the method crypto.randomBytes
that generates a random Buffer. However, the base64 encoding in node is not url-safe, it includes /
and +
instead of -
and _
. Therefore, the easiest way to generate such token I've found is
require('crypto').randomBytes(48, function(ex, buf) {
token = buf.toString('base64').replace(/\//g,'_').replace(/\+/g,'-');
});
Is there a more elegant way?
This question is related to
javascript
node.js
base64
securestring
Simple function that gets you a token that is URL safe and has base64 encoding! It's a combination of 2 answers from above.
const randomToken = () => {
crypto.randomBytes(64).toString('base64').replace(/\//g,'_').replace(/\+/g,'-');
}
With async/await and promisification.
const crypto = require('crypto')
const randomBytes = Util.promisify(crypto.randomBytes)
const plain = (await randomBytes(24)).toString('base64').replace(/\W/g, '')
Generates something similar to VjocVHdFiz5vGHnlnwqJKN0NdeHcz8eM
crypto-random-string is a nice module for this.
const cryptoRandomString = require('crypto-random-string');
cryptoRandomString({length: 10});
// => '2cf05d94db'
cryptoRandomString({length: 10, type: 'base64'});
// => 'YMiMbaQl6I'
cryptoRandomString({length: 10, type: 'url-safe'});
// => 'YN-tqc8pOw'
cryptoRandomString({length: 10, type: 'numeric'});
// => '8314659141'
cryptoRandomString({length: 6, type: 'distinguishable'});
// => 'CDEHKM'
cryptoRandomString({length: 10, type: 'ascii-printable'});
// => '`#Rt8$IK>B'
cryptoRandomString({length: 10, type: 'alphanumeric'});
// => 'DMuKL8YtE7'
cryptoRandomString({length: 10, characters: 'abc'});
// => 'abaaccabac'
cryptoRandomString.async(options)
add .async
if you want to get a promise
.
The up-to-date right way to do this asynchronously using ES 2016 standards of async and await (as of Node 7) would be the following:
const crypto = require('crypto');
function generateToken({ stringBase = 'base64', byteLength = 48 } = {}) {
return new Promise((resolve, reject) => {
crypto.randomBytes(byteLength, (err, buffer) => {
if (err) {
reject(err);
} else {
resolve(buffer.toString(stringBase));
}
});
});
}
async function handler(req, res) {
// default token length
const newToken = await generateToken();
console.log('newToken', newToken);
// pass in parameters - adjust byte length
const shortToken = await generateToken({byteLength: 20});
console.log('newToken', shortToken);
}
This works out of the box in Node 7 without any Babel transformations
Synchronous option in-case if you are not a JS expert like me. Had to spend some time on how to access the inline function variable
var token = crypto.randomBytes(64).toString('hex');
The npm module anyid provides flexible API to generate various kinds of string ID / code.
To generate random string in A-Za-z0-9 using 48 random bytes:
const id = anyid().encode('Aa0').bits(48 * 8).random().id();
// G4NtiI9OYbSgVl3EAkkoxHKyxBAWzcTI7aH13yIUNggIaNqPQoSS7SpcalIqX0qGZ
To generate fixed length alphabet only string filled by random bytes:
const id = anyid().encode('Aa').length(20).random().id();
// qgQBBtDwGMuFHXeoVLpt
Internally it uses crypto.randomBytes()
to generate random.
Random URL and filename string safe (1 liner)
Crypto.randomBytes(48).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
Check out:
var crypto = require('crypto');
crypto.randomBytes(Math.ceil(length/2)).toString('hex').slice(0,length);
https://www.npmjs.com/package/crypto-extra has a method for it :)
var value = crypto.random(/* desired length */)
A tiny, secure, URL-friendly, unique string ID generator for JavaScript
import { nanoid } from "nanoid";
const id = nanoid(48);
Page 7 of RCF 4648 describes how to encode in base 64 with URL safety. You can use an existing library like base64url to do the job.
The function will be:
var crypto = require('crypto');
var base64url = require('base64url');
/** Sync */
function randomStringAsBase64Url(size) {
return base64url(crypto.randomBytes(size));
}
Usage example:
randomStringAsBase64Url(20);
// Returns 'AXSGpLVjne_f7w5Xg-fWdoBwbfs' which is 27 characters length.
Note that the returned string length will not match with the size argument (size != final length).
Beware that with this solution the generated random string is not uniformly distributed.
You can also build a strong random string from a limited set of characters like that:
var crypto = require('crypto');
/** Sync */
function randomString(length, chars) {
if (!chars) {
throw new Error('Argument \'chars\' is undefined');
}
var charsLength = chars.length;
if (charsLength > 256) {
throw new Error('Argument \'chars\' should not have more than 256 characters'
+ ', otherwise unpredictability will be broken');
}
var randomBytes = crypto.randomBytes(length);
var result = new Array(length);
var cursor = 0;
for (var i = 0; i < length; i++) {
cursor += randomBytes[i];
result[i] = chars[cursor % charsLength];
}
return result.join('');
}
/** Sync */
function randomAsciiString(length) {
return randomString(length,
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');
}
Usage example:
randomAsciiString(20);
// Returns 'rmRptK5niTSey7NlDk5y' which is 20 characters length.
randomString(20, 'ABCDEFG');
// Returns 'CCBAAGDGBBEGBDBECDCE' which is 20 characters length.
Look at real_ates
ES2016 way, it's more correct.
import crypto from 'crypto';
function spawnTokenBuf() {
return function(callback) {
crypto.randomBytes(48, callback);
};
}
async function() {
console.log((await spawnTokenBuf()).toString('base64'));
};
var crypto = require('crypto');
var co = require('co');
function spawnTokenBuf() {
return function(callback) {
crypto.randomBytes(48, callback);
};
}
co(function* () {
console.log((yield spawnTokenBuf()).toString('base64'));
});
Source: Stackoverflow.com