jsonwebtoken
Advanced tools
Comparing version 8.2.2 to 8.3.0
@@ -7,2 +7,10 @@ # Change Log | ||
## 8.3.0 - 2018-06-11 | ||
- docs: add some clarifications (#473) ([cd33cc81f06068b9df6c224d300dc6f70d8904ab](https://github.com/auth0/node-jsonwebtoken/commit/cd33cc81f06068b9df6c224d300dc6f70d8904ab)), closes [#473](https://github.com/auth0/node-jsonwebtoken/issues/473) | ||
- ci: fix ci execution, remove not needed script (#472) ([c8ff7b2c3ffcd954a64a0273c20a7d1b22339aa5](https://github.com/auth0/node-jsonwebtoken/commit/c8ff7b2c3ffcd954a64a0273c20a7d1b22339aa5)), closes [#472](https://github.com/auth0/node-jsonwebtoken/issues/472) | ||
- new feature: Secret callback revisited (#480) ([d01cc7bcbdeb606d997a580f967b3169fcc622ba](https://github.com/auth0/node-jsonwebtoken/commit/d01cc7bcbdeb606d997a580f967b3169fcc622ba)), closes [#480](https://github.com/auth0/node-jsonwebtoken/issues/480) | ||
- docs:Update README.md (#461) ([f0e0954505f274da95a8d9603598e455b4d2c894](https://github.com/auth0/node-jsonwebtoken/commit/f0e0954505f274da95a8d9603598e455b4d2c894)), closes [#461](https://github.com/auth0/node-jsonwebtoken/issues/461) | ||
## 8.2.2 - 2018-05-30 | ||
@@ -9,0 +17,0 @@ |
{ | ||
"name": "jsonwebtoken", | ||
"version": "8.2.2", | ||
"version": "8.3.0", | ||
"description": "JSON Web Token implementation (symmetric and asymmetric)", | ||
@@ -30,4 +30,3 @@ "main": "index.js", | ||
"lodash.once": "^4.0.0", | ||
"ms": "^2.1.1", | ||
"xtend": "^4.0.1" | ||
"ms": "^2.1.1" | ||
}, | ||
@@ -34,0 +33,0 @@ "devDependencies": { |
@@ -125,2 +125,3 @@ # jsonwebtoken | ||
encoded public key for RSA and ECDSA. | ||
If `jwt.verify` is called asynchronous, `secretOrPublicKey` can be a function that should fetch the secret or public key. See below for a detailed example | ||
@@ -201,2 +202,19 @@ As mentioned in [this comment](https://github.com/auth0/node-jsonwebtoken/issues/208#issuecomment-231861138), there are other libraries that expect base64 encoded secrets (random bytes encoded using base64), if that is your case you can pass `Buffer.from(secret, 'base64')`, by doing this the secret will be decoded using base64 and the token verification will use the original random bytes. | ||
// Verify using getKey callback | ||
// Example uses https://github.com/auth0/node-jwks-rsa as a way to fetch the keys. | ||
var jwksClient = require('jwks-rsa'); | ||
var client = jwksClient({ | ||
jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json' | ||
}); | ||
function getKey(header, callback){ | ||
client.getSigningKey(header.kid, function(err, key) { | ||
var signingKey = key.publicKey || key.rsaPublicKey; | ||
callback(null, signingKey); | ||
}); | ||
} | ||
jwt.verify(token, getKey, options, function(err, decoded) { | ||
console.log(decoded.foo) // bar | ||
}); | ||
``` | ||
@@ -203,0 +221,0 @@ |
var timespan = require('./lib/timespan'); | ||
var xtend = require('xtend'); | ||
var jws = require('jws'); | ||
@@ -88,3 +87,3 @@ var includes = require('lodash.includes'); | ||
var header = xtend({ | ||
var header = Object.assign({ | ||
alg: options.algorithm || 'HS256', | ||
@@ -116,3 +115,3 @@ typ: isObjectPayload ? 'JWT' : undefined, | ||
if (!options.mutatePayload) { | ||
payload = xtend(payload); | ||
payload = Object.assign({},payload); | ||
} | ||
@@ -119,0 +118,0 @@ } else { |
201
verify.js
@@ -7,3 +7,2 @@ var JsonWebTokenError = require('./lib/JsonWebTokenError'); | ||
var jws = require('jws'); | ||
var xtend = require('xtend'); | ||
@@ -21,3 +20,4 @@ module.exports = function (jwtString, secretOrPublicKey, options, callback) { | ||
//clone this object since we are going to mutate it. | ||
options = xtend(options); | ||
options = Object.assign({}, options); | ||
var done; | ||
@@ -54,29 +54,6 @@ | ||
var hasSignature = parts[2].trim() !== ''; | ||
var decodedToken; | ||
if (!hasSignature && secretOrPublicKey){ | ||
return done(new JsonWebTokenError('jwt signature is required')); | ||
} | ||
if (hasSignature && !secretOrPublicKey) { | ||
return done(new JsonWebTokenError('secret or public key must be provided')); | ||
} | ||
if (!hasSignature && !options.algorithms) { | ||
options.algorithms = ['none']; | ||
} | ||
if (!options.algorithms) { | ||
options.algorithms = ~secretOrPublicKey.toString().indexOf('BEGIN CERTIFICATE') || | ||
~secretOrPublicKey.toString().indexOf('BEGIN PUBLIC KEY') ? | ||
[ 'RS256','RS384','RS512','ES256','ES384','ES512' ] : | ||
~secretOrPublicKey.toString().indexOf('BEGIN RSA PUBLIC KEY') ? | ||
[ 'RS256','RS384','RS512' ] : | ||
[ 'HS256','HS384','HS512' ]; | ||
} | ||
var decodedToken; | ||
try { | ||
decodedToken = jws.decode(jwtString); | ||
decodedToken = decode(jwtString, { complete: true }); | ||
} catch(err) { | ||
@@ -91,95 +68,135 @@ return done(err); | ||
var header = decodedToken.header; | ||
var getSecret; | ||
if (!~options.algorithms.indexOf(header.alg)) { | ||
return done(new JsonWebTokenError('invalid algorithm')); | ||
} | ||
if(typeof secretOrPublicKey === 'function') { | ||
if(!callback) { | ||
return done(new JsonWebTokenError('verify must be called asynchronous if secret or public key is provided as a callback')); | ||
} | ||
var valid; | ||
try { | ||
valid = jws.verify(jwtString, header.alg, secretOrPublicKey); | ||
} catch (e) { | ||
return done(e); | ||
getSecret = secretOrPublicKey; | ||
} | ||
else { | ||
getSecret = function(header, secretCallback) { | ||
return secretCallback(null, secretOrPublicKey); | ||
}; | ||
} | ||
if (!valid) | ||
return done(new JsonWebTokenError('invalid signature')); | ||
return getSecret(header, function(err, secretOrPublicKey) { | ||
if(err) { | ||
return done(new JsonWebTokenError('error in secret or public key callback: ' + err.message)); | ||
} | ||
var payload; | ||
var hasSignature = parts[2].trim() !== ''; | ||
try { | ||
payload = decode(jwtString); | ||
} catch(err) { | ||
return done(err); | ||
} | ||
if (!hasSignature && secretOrPublicKey){ | ||
return done(new JsonWebTokenError('jwt signature is required')); | ||
} | ||
if (typeof payload.nbf !== 'undefined' && !options.ignoreNotBefore) { | ||
if (typeof payload.nbf !== 'number') { | ||
return done(new JsonWebTokenError('invalid nbf value')); | ||
if (hasSignature && !secretOrPublicKey) { | ||
return done(new JsonWebTokenError('secret or public key must be provided')); | ||
} | ||
if (payload.nbf > clockTimestamp + (options.clockTolerance || 0)) { | ||
return done(new NotBeforeError('jwt not active', new Date(payload.nbf * 1000))); | ||
if (!hasSignature && !options.algorithms) { | ||
options.algorithms = ['none']; | ||
} | ||
} | ||
if (typeof payload.exp !== 'undefined' && !options.ignoreExpiration) { | ||
if (typeof payload.exp !== 'number') { | ||
return done(new JsonWebTokenError('invalid exp value')); | ||
if (!options.algorithms) { | ||
options.algorithms = ~secretOrPublicKey.toString().indexOf('BEGIN CERTIFICATE') || | ||
~secretOrPublicKey.toString().indexOf('BEGIN PUBLIC KEY') ? | ||
['RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512'] : | ||
~secretOrPublicKey.toString().indexOf('BEGIN RSA PUBLIC KEY') ? | ||
['RS256', 'RS384', 'RS512'] : | ||
['HS256', 'HS384', 'HS512']; | ||
} | ||
if (clockTimestamp >= payload.exp + (options.clockTolerance || 0)) { | ||
return done(new TokenExpiredError('jwt expired', new Date(payload.exp * 1000))); | ||
if (!~options.algorithms.indexOf(decodedToken.header.alg)) { | ||
return done(new JsonWebTokenError('invalid algorithm')); | ||
} | ||
} | ||
if (options.audience) { | ||
var audiences = Array.isArray(options.audience)? options.audience : [options.audience]; | ||
var target = Array.isArray(payload.aud) ? payload.aud : [payload.aud]; | ||
var valid; | ||
var match = target.some(function(targetAudience) { | ||
return audiences.some(function(audience) { | ||
return audience instanceof RegExp ? audience.test(targetAudience) : audience === targetAudience; | ||
}); | ||
}); | ||
try { | ||
valid = jws.verify(jwtString, decodedToken.header.alg, secretOrPublicKey); | ||
} catch (e) { | ||
return done(e); | ||
} | ||
if (!match) | ||
return done(new JsonWebTokenError('jwt audience invalid. expected: ' + audiences.join(' or '))); | ||
} | ||
if (!valid) { | ||
return done(new JsonWebTokenError('invalid signature')); | ||
} | ||
if (options.issuer) { | ||
var invalid_issuer = | ||
(typeof options.issuer === 'string' && payload.iss !== options.issuer) || | ||
(Array.isArray(options.issuer) && options.issuer.indexOf(payload.iss) === -1); | ||
var payload = decodedToken.payload; | ||
if (invalid_issuer) { | ||
return done(new JsonWebTokenError('jwt issuer invalid. expected: ' + options.issuer)); | ||
if (typeof payload.nbf !== 'undefined' && !options.ignoreNotBefore) { | ||
if (typeof payload.nbf !== 'number') { | ||
return done(new JsonWebTokenError('invalid nbf value')); | ||
} | ||
if (payload.nbf > clockTimestamp + (options.clockTolerance || 0)) { | ||
return done(new NotBeforeError('jwt not active', new Date(payload.nbf * 1000))); | ||
} | ||
} | ||
} | ||
if (options.subject) { | ||
if (payload.sub !== options.subject) { | ||
return done(new JsonWebTokenError('jwt subject invalid. expected: ' + options.subject)); | ||
if (typeof payload.exp !== 'undefined' && !options.ignoreExpiration) { | ||
if (typeof payload.exp !== 'number') { | ||
return done(new JsonWebTokenError('invalid exp value')); | ||
} | ||
if (clockTimestamp >= payload.exp + (options.clockTolerance || 0)) { | ||
return done(new TokenExpiredError('jwt expired', new Date(payload.exp * 1000))); | ||
} | ||
} | ||
} | ||
if (options.jwtid) { | ||
if (payload.jti !== options.jwtid) { | ||
return done(new JsonWebTokenError('jwt jwtid invalid. expected: ' + options.jwtid)); | ||
if (options.audience) { | ||
var audiences = Array.isArray(options.audience) ? options.audience : [options.audience]; | ||
var target = Array.isArray(payload.aud) ? payload.aud : [payload.aud]; | ||
var match = target.some(function (targetAudience) { | ||
return audiences.some(function (audience) { | ||
return audience instanceof RegExp ? audience.test(targetAudience) : audience === targetAudience; | ||
}); | ||
}); | ||
if (!match) { | ||
return done(new JsonWebTokenError('jwt audience invalid. expected: ' + audiences.join(' or '))); | ||
} | ||
} | ||
} | ||
if (options.maxAge) { | ||
if (typeof payload.iat !== 'number') { | ||
return done(new JsonWebTokenError('iat required when maxAge is specified')); | ||
if (options.issuer) { | ||
var invalid_issuer = | ||
(typeof options.issuer === 'string' && payload.iss !== options.issuer) || | ||
(Array.isArray(options.issuer) && options.issuer.indexOf(payload.iss) === -1); | ||
if (invalid_issuer) { | ||
return done(new JsonWebTokenError('jwt issuer invalid. expected: ' + options.issuer)); | ||
} | ||
} | ||
var maxAgeTimestamp = timespan(options.maxAge, payload.iat); | ||
if (typeof maxAgeTimestamp === 'undefined') { | ||
return done(new JsonWebTokenError('"maxAge" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60')); | ||
if (options.subject) { | ||
if (payload.sub !== options.subject) { | ||
return done(new JsonWebTokenError('jwt subject invalid. expected: ' + options.subject)); | ||
} | ||
} | ||
if (clockTimestamp >= maxAgeTimestamp + (options.clockTolerance || 0)) { | ||
return done(new TokenExpiredError('maxAge exceeded', new Date(maxAgeTimestamp * 1000))); | ||
if (options.jwtid) { | ||
if (payload.jti !== options.jwtid) { | ||
return done(new JsonWebTokenError('jwt jwtid invalid. expected: ' + options.jwtid)); | ||
} | ||
} | ||
} | ||
return done(null, payload); | ||
if (options.maxAge) { | ||
if (typeof payload.iat !== 'number') { | ||
return done(new JsonWebTokenError('iat required when maxAge is specified')); | ||
} | ||
var maxAgeTimestamp = timespan(options.maxAge, payload.iat); | ||
if (typeof maxAgeTimestamp === 'undefined') { | ||
return done(new JsonWebTokenError('"maxAge" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60')); | ||
} | ||
if (clockTimestamp >= maxAgeTimestamp + (options.clockTolerance || 0)) { | ||
return done(new TokenExpiredError('maxAge exceeded', new Date(maxAgeTimestamp * 1000))); | ||
} | ||
} | ||
return done(null, payload); | ||
}); | ||
}; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
62042
9
399
338
- Removedxtend@^4.0.1
- Removedxtend@4.0.2(transitive)