secure-token
Version:
Simple, secure tokens for authentication, access keys, sessions etc.
42 lines (33 loc) • 1.52 kB
JavaScript
var sodium = require('sodium-native')
var assert = require('nanoassert')
var APPTOKEN_BYTES_MIN = 16 // 128 bits
var APPTOKEN_BYTES = 18 // fits into base64 encoding without padding
// Why 18? Because 18 bytes > 128 bits, making an adversary do at least 2^64
// attempts before finding a hash collision, ie. being able to fake a token
// 18 is the first number after 16 (128 bits) where `x mod 6 = 0`,
// meaning it base64 encodes without padding
function create (size) {
assert(size == null ? true : size >= APPTOKEN_BYTES_MIN, 'size must be at least APPTOKEN_BYTES_MIN (' + APPTOKEN_BYTES_MIN + ')')
assert(size == null ? true : Number.isSafeInteger(size), 'size must be safe integer')
var res = Buffer.alloc(size || APPTOKEN_BYTES)
sodium.randombytes_buf(res)
return res
}
var EMPTY_BUF = Buffer.alloc(0)
// namespace can be used to seperate different various token uses eg. session,
// access, deploy etc.
function hash (tokenBuf, namespace) {
assert(Buffer.isBuffer(tokenBuf), 'tokenBuf must be Buffer')
if (namespace == null) namespace = EMPTY_BUF
if (typeof namespace === 'string') namespace = Buffer.from(namespace)
assert(namespace == null ? true : Buffer.isBuffer(namespace), 'namespace must be Buffer')
var output = Buffer.alloc(sodium.crypto_generichash_BYTES)
sodium.crypto_generichash(output, Buffer.concat([namespace, tokenBuf]))
return output
}
module.exports = {
create: create,
hash: hash,
APPTOKEN_BYTES_MIN: APPTOKEN_BYTES_MIN,
APPTOKEN_BYTES: APPTOKEN_BYTES
}