Comparing version 1.0.0 to 1.1.0
68
index.js
const path = require('path'); | ||
const exec = require('child_process').exec; | ||
const jwa = require('jwa'); | ||
const Qlru = require('quick-lru'); | ||
const cache = require('kitten-cache'); | ||
// default expiration of token in seconds | ||
const DEFAULT_EXPIRE_IN = 60 * 60 * 12; | ||
const ALGORITHM_BITS = '512'; | ||
@@ -13,14 +11,47 @@ const ALGORITHM_NAME = 'ES'+ALGORITHM_BITS; | ||
const CLIENT_CACHE_SIZE_MAX = 200; | ||
const clientCache = new Qlru({maxSize : CLIENT_CACHE_SIZE_MAX}); | ||
// how many time before expiration do we renew the token in millisecond | ||
const CLIENT_RENEW_LIMIT = 60 * 20 * 1000; | ||
const TOKEN_COOKIE_REGEXP = /access_token\s*=([^;]+?)(?:;|$)/; | ||
let params = { | ||
// client cache size used by getToken | ||
clientCacheSize : 5, | ||
// how many time before expiration do we renew the token in millisecond | ||
clientRenewTokenBeforeExp : 60 * 20 * 1000, | ||
// default expiration of token in seconds | ||
clientTokenExpiration : 60 * 60 * 12, | ||
// server cache size used by verifyHTTPHeaderFn | ||
serverCacheSize : 5 | ||
}; | ||
const SERVER_CACHE_SIZE_MAX = 1000; | ||
const serverCache = new Qlru({maxSize : SERVER_CACHE_SIZE_MAX}); | ||
let clientCache = new cache({size : params.clientCacheSize}); | ||
let serverCache = new cache({size : params.serverCacheSize}); | ||
const TOKEN_COOKIE_REGEXP = /access_token\s*=([^;]+?)(?:;|$)/; | ||
/** | ||
* Sets options | ||
* | ||
* @param {Object} options : { | ||
* // client cache size used by getToken | ||
* clientCacheSize : 5, | ||
* // how many time before token expiration do we renew the token in millisecond | ||
* clientRenewTokenBeforeExp : 60 * 20 * 1000, | ||
* // default expiration of token in seconds | ||
* clientTokenExpiration : 60 * 60 * 12, | ||
* // server cache size used by verifyHTTPHeaderFn | ||
* serverCacheSize : 5 | ||
* } | ||
*/ | ||
function set (options) { | ||
for(let _attr in options) { | ||
if (params[_attr] !== undefined) { | ||
params[_attr] = options[_attr] | ||
} | ||
} | ||
// reset cache only if clientCacheSize or serverCacheSize changes | ||
if (options.clientCacheSize || options.serverCacheSize) { | ||
clientCache = new cache({size : params.clientCacheSize}); | ||
serverCache = new cache({size : params.serverCacheSize}); | ||
} | ||
} | ||
/** | ||
* Decode base64 url if there is in the token | ||
@@ -114,4 +145,5 @@ * | ||
* @param {Function} callback(err, parsedPayload) | ||
* @param {Integer} now Current timestamp in ms | ||
*/ | ||
function parseToken (jwt, callback) { | ||
function parseToken (jwt, callback, now = Date.now()) { | ||
let _segments = jwt.split('.'); | ||
@@ -150,3 +182,3 @@ if (_segments.length !== 3) { | ||
if (_payload.exp && Date.now() > parseInt(_payload.exp, 10) * 1000) { | ||
if (_payload.exp && now > parseInt(_payload.exp, 10) * 1000) { | ||
return callback(new Error('JSON Web Token expired')); | ||
@@ -192,4 +224,5 @@ } | ||
* @param {Function} callback(err, parsedPayload) | ||
* @param {Integer} now Current timestamp in ms | ||
*/ | ||
function verify (jwt, publicKey, callback) { | ||
function verify (jwt, publicKey, callback, now = Date.now()) { | ||
parseToken(jwt, (err, payload, tokenString, signature) => { | ||
@@ -200,3 +233,3 @@ if (err) { | ||
return verifyToken(payload, tokenString, signature, publicKey, callback); | ||
}); | ||
}, now); | ||
} | ||
@@ -217,6 +250,6 @@ | ||
let _now = Date.now(); | ||
if ( _cachedToken !== undefined && _now < (_cachedToken.expireAt - CLIENT_RENEW_LIMIT) && _cachedToken.privKey === privKey ) { | ||
if ( _cachedToken !== undefined && _now < (_cachedToken.expireAt - params.clientRenewTokenBeforeExp) && _cachedToken.privKey === privKey ) { | ||
return _cachedToken.token; | ||
} | ||
let _newToken = generate(clientId, serverId, DEFAULT_EXPIRE_IN, privKey, data); | ||
let _newToken = generate(clientId, serverId, params.clientTokenExpiration, privKey, data); | ||
@@ -226,3 +259,3 @@ clientCache.set(_cacheKey, { | ||
privKey : privKey, | ||
expireAt : _now + (DEFAULT_EXPIRE_IN * 1000) | ||
expireAt : _now + (params.clientTokenExpiration * 1000) | ||
}); | ||
@@ -361,2 +394,3 @@ | ||
module.exports = { | ||
set, | ||
verify, | ||
@@ -363,0 +397,0 @@ verifyHTTPHeaderFn, |
{ | ||
"name": "kitten-jwt", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "Keep It Simple, Stupid, Secure and Fast JWT module", | ||
@@ -30,4 +30,4 @@ "main": "index.js", | ||
"jwa": "1.1.6", | ||
"quick-lru": "2.0.0" | ||
"kitten-cache": "0.3.0" | ||
} | ||
} |
@@ -32,3 +32,3 @@ # Kitten JWT | ||
- Fastify, Restify or Express authentication middleware | ||
- Highly secured by default with assymetric ECDSA keys (ES512) | ||
- Highly secured by default with asymmetric ECDSA keys (ES512) | ||
- ECDSA Public / Private key generator | ||
@@ -142,3 +142,3 @@ | ||
- getPublicKeyFn : Function(req, res, payload, callback) which must call the `callback(String|Array)` where | ||
the parameter is either a string (one public key) or an array of strings (mutliple public key to test) | ||
the parameter is either a string (one public key) or an array of strings (multiple public key to test) | ||
- serverId : JWT audience, token.aud | ||
@@ -152,3 +152,3 @@ if the token is invalid, next(err) is called. Thus you can catch the error in another 4-parameter middlewares. | ||
These APIs should **not be used direclty in a web app because nothing is cached (slow)**. | ||
These APIs should **not be used directly in a web app because nothing is cached (slow)**. | ||
@@ -165,3 +165,3 @@ * `jwt.generate (clientId, serverId, expiresIn, privKey, data)` : generate a token | ||
* `jwt.verify (jwt, pubKey, callback)` : verify the signature of a token | ||
* `jwt.verify (jwt, pubKey, callback, now = Date.now())` : verify the signature of a token | ||
@@ -171,5 +171,19 @@ - jwt : JSON Web token string to verify | ||
- callback (err, payload) : callback, payload is an object | ||
- now : current timestamp used to check if the token is expired | ||
* `jwt.generateKeys (outputDir, outputKeyName)` : generate pub / priv ECDSA keys | ||
* `jwt.set (options)` : set default options: | ||
```js | ||
{ | ||
// client cache size used by getToken | ||
clientCacheSize : 5, | ||
// how many time before client token expiration kitten-cache renews tokens in millisecond | ||
clientRenewTokenBeforeExp : 60 * 20 * 1000, | ||
// default client tokens expiration in seconds | ||
clientTokenExpiration : 60 * 60 * 12, | ||
// server cache size used by verifyHTTPHeaderFn | ||
serverCacheSize : 5 | ||
} | ||
``` | ||
@@ -179,2 +193,8 @@ | ||
**1.1.0** | ||
- replace quick-lru by kitten-cache (faster, lower memory consumption) | ||
- change default cache size with new function `set(options)` | ||
- WARNING: reduce server/client cache size to 5 by default to reduce memory consumption | ||
- set current timestamp in `verify` function | ||
**1.0.0** | ||
@@ -193,3 +213,3 @@ | ||
- to save extra bandwithh: kitten-jwt accepts and generate tokens with one-letter header instead of RFCs JWT header (optional) | ||
- to save extra bandwidth: kitten-jwt accepts and generate tokens with one-letter header instead of RFCs JWT header (optional) | ||
- make expiration a little bit random | ||
@@ -196,0 +216,0 @@ - should i use https://en.wikipedia.org/wiki/Curve25519 ? |
32142
356
213
+ Addedkitten-cache@0.3.0
+ Addedkitten-cache@0.3.0(transitive)
- Removedquick-lru@2.0.0
- Removedquick-lru@2.0.0(transitive)