mirror of
https://github.com/hanzoai/node-jsonwebtoken.git
synced 2026-09-24 17:00:48 +00:00
Merge branch 'master' of https://github.com/TATDK/node-jsonwebtoken into TATDK-master
Conflicts: README.md index.js
This commit is contained in:
@@ -28,16 +28,19 @@ encoded private key for RSA and ECDSA.
|
||||
|
||||
* `algorithm` (default: `HS256`)
|
||||
* `expiresIn`: expressed in seconds or an string describing a time span [rauchg/ms](https://github.com/rauchg/ms.js). Eg: `60`, `"2 days"`, `"10h"`, `"7d"`
|
||||
* `notBeforeMinutes` or `notBeforeSeconds`
|
||||
* `audience`
|
||||
* `subject`
|
||||
* `issuer`
|
||||
* `jwtid`
|
||||
* `subject`
|
||||
* `noTimestamp`
|
||||
* `headers`
|
||||
|
||||
If `payload` is not a buffer or a string, it will be coerced into a string
|
||||
using `JSON.stringify`.
|
||||
|
||||
If any `expiresIn`, `audience`, `subject`, `issuer` are not provided, there is no default. The jwt generated won't include those properties in the payload.
|
||||
If any `expiresIn`, `notBeforeMinutes`, `audience`, `subject`, `issuer` are not provided, there is no default. The jwt generated won't include those properties in the payload.
|
||||
|
||||
Additional headers can be provided via the `headers` object.
|
||||
|
||||
@@ -77,7 +80,9 @@ encoded public key for RSA and ECDSA.
|
||||
* `audience`: if you want to check audience (`aud`), provide a value here
|
||||
* `issuer`: if you want to check issuer (`iss`), provide a value here
|
||||
* `ignoreExpiration`: if `true` do not validate the expiration of the token.
|
||||
* `maxAge`: optional sets an expiration based on the `iat` field. Eg `2h`
|
||||
* `ignoreNotBefore`...
|
||||
* `jwtid`: if you want to check JWT ID (`jti`), provide a value here
|
||||
* `subject`: if you want to check subject (`sub`), provide a value here
|
||||
|
||||
```js
|
||||
// verify a token symmetric - synchronous
|
||||
@@ -120,6 +125,18 @@ jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer' }, function(
|
||||
// if issuer mismatch, err == invalid issuer
|
||||
});
|
||||
|
||||
// verify jwt id
|
||||
var cert = fs.readFileSync('public.pem'); // get public key
|
||||
jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid' }, function(err, decoded) {
|
||||
// if jwt id mismatch, err == invalid jwt id
|
||||
});
|
||||
|
||||
// verify subject
|
||||
var cert = fs.readFileSync('public.pem'); // get public key
|
||||
jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid', subject: 'subject' }, function(err, decoded) {
|
||||
// if subject mismatch, err == invalid subject
|
||||
});
|
||||
|
||||
// alg mismatch
|
||||
var cert = fs.readFileSync('public.pem'); // get public key
|
||||
jwt.verify(token, cert, { algorithms: ['RS256'] }, function (err, payload) {
|
||||
@@ -191,6 +208,8 @@ Error object:
|
||||
* 'invalid signature'
|
||||
* 'jwt audience invalid. expected: [OPTIONS AUDIENCE]'
|
||||
* 'jwt issuer invalid. expected: [OPTIONS ISSUER]'
|
||||
* 'jwt id invalid. expected: [OPTIONS JWT ID]'
|
||||
* 'jwt subject invalid. expected: [OPTIONS SUBJECT]'
|
||||
|
||||
```js
|
||||
jwt.verify(token, 'shhhhh', function(err, decoded) {
|
||||
|
||||
@@ -4,6 +4,7 @@ var ms = require('ms');
|
||||
var JWT = module.exports;
|
||||
|
||||
var JsonWebTokenError = JWT.JsonWebTokenError = require('./lib/JsonWebTokenError');
|
||||
var NotBeforeError = module.exports.NotBeforeError = require('./lib/NotBeforeError');
|
||||
var TokenExpiredError = JWT.TokenExpiredError = require('./lib/TokenExpiredError');
|
||||
|
||||
JWT.decode = function (jwt, options) {
|
||||
@@ -56,6 +57,14 @@ JWT.sign = function(payload, secretOrPrivateKey, options, callback) {
|
||||
if (!options.noTimestamp) {
|
||||
payload.iat = payload.iat || timestamp;
|
||||
}
|
||||
|
||||
var notBeforeSeconds = options.notBeforeMinutes ?
|
||||
options.notBeforeMinutes * 60 :
|
||||
options.notBeforeSeconds;
|
||||
|
||||
if (notBeforeSeconds) {
|
||||
payload.nbf = timestamp + notBeforeSeconds;
|
||||
}
|
||||
|
||||
if (options.expiresInSeconds || options.expiresInMinutes) {
|
||||
var deprecated_line;
|
||||
@@ -96,6 +105,9 @@ JWT.sign = function(payload, secretOrPrivateKey, options, callback) {
|
||||
if (options.subject)
|
||||
payload.sub = options.subject;
|
||||
|
||||
if (options.jwtid)
|
||||
payload.jti = options.jwtid;
|
||||
|
||||
var encoding = 'utf8';
|
||||
if (options.encoding) {
|
||||
encoding = options.encoding;
|
||||
@@ -199,6 +211,14 @@ JWT.verify = function(jwtString, secretOrPublicKey, options, callback) {
|
||||
} catch(err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
if (typeof payload.nbf !== 'undefined' && !options.ignoreNotBefore) {
|
||||
if (typeof payload.nbf !== 'number') {
|
||||
return done(new JsonWebTokenError('invalid nbf value'));
|
||||
}
|
||||
if (payload.nbf >= Math.floor(Date.now() / 1000))
|
||||
return done(new NotBeforeError('jwt not active', new Date(payload.nbf * 1000)));
|
||||
}
|
||||
|
||||
if (typeof payload.exp !== 'undefined' && !options.ignoreExpiration) {
|
||||
if (typeof payload.exp !== 'number') {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
var JsonWebTokenError = require('./JsonWebTokenError');
|
||||
|
||||
var NotBeforeError = function (message, date) {
|
||||
JsonWebTokenError.call(this, message);
|
||||
this.name = 'NotBeforeError';
|
||||
this.date = date;
|
||||
};
|
||||
|
||||
NotBeforeError.prototype = Object.create(JsonWebTokenError.prototype);
|
||||
|
||||
NotBeforeError.prototype.constructor = NotBeforeError;
|
||||
|
||||
module.exports = NotBeforeError;
|
||||
@@ -88,6 +88,43 @@ describe('RS256', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when signing a token with not before', function() {
|
||||
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBeforeMinutes: -10 });
|
||||
|
||||
it('should be valid expiration', function(done) {
|
||||
jwt.verify(token, pub, function(err, decoded) {
|
||||
assert.isNotNull(decoded);
|
||||
assert.isNull(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be invalid', function(done) {
|
||||
// not active token
|
||||
token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBeforeMinutes: 10 });
|
||||
|
||||
jwt.verify(token, pub, function(err, decoded) {
|
||||
assert.isUndefined(decoded);
|
||||
assert.isNotNull(err);
|
||||
assert.equal(err.name, 'NotBeforeError');
|
||||
assert.instanceOf(err.date, Date);
|
||||
assert.instanceOf(err, jwt.NotBeforeError);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should NOT be invalid', function(done) {
|
||||
// not active token
|
||||
token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBeforeMinutes: 10 });
|
||||
|
||||
jwt.verify(token, pub, { ignoreNotBefore: true }, function(err, decoded) {
|
||||
assert.ok(decoded.foo);
|
||||
assert.equal('bar', decoded.foo);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when signing a token with audience', function() {
|
||||
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', audience: 'urn:foo' });
|
||||
|
||||
@@ -236,6 +273,72 @@ describe('RS256', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when signing a token with subject', function() {
|
||||
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', subject: 'subject' });
|
||||
|
||||
it('should check subject', function() {
|
||||
jwt.verify(token, pub, { subject: 'subject' }, function(err, decoded) {
|
||||
assert.isNotNull(decoded);
|
||||
assert.isNull(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw when invalid subject', function() {
|
||||
jwt.verify(token, pub, { issuer: 'wrongSubject' }, function(err, decoded) {
|
||||
assert.isUndefined(decoded);
|
||||
assert.isNotNull(err);
|
||||
assert.equal(err.name, 'JsonWebTokenError');
|
||||
assert.instanceOf(err, jwt.JsonWebTokenError);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when signing a token without subject', function() {
|
||||
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
|
||||
|
||||
it('should check subject', function() {
|
||||
jwt.verify(token, pub, { subject: 'subject' }, function(err, decoded) {
|
||||
assert.isUndefined(decoded);
|
||||
assert.isNotNull(err);
|
||||
assert.equal(err.name, 'JsonWebTokenError');
|
||||
assert.instanceOf(err, jwt.JsonWebTokenError);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when signing a token with jwt id', function() {
|
||||
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', jwtid: 'jwtid' });
|
||||
|
||||
it('should check jwt id', function() {
|
||||
jwt.verify(token, pub, { jwtid: 'jwtid' }, function(err, decoded) {
|
||||
assert.isNotNull(decoded);
|
||||
assert.isNull(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw when invalid jwt id', function() {
|
||||
jwt.verify(token, pub, { jwtid: 'wrongJwtid' }, function(err, decoded) {
|
||||
assert.isUndefined(decoded);
|
||||
assert.isNotNull(err);
|
||||
assert.equal(err.name, 'JsonWebTokenError');
|
||||
assert.instanceOf(err, jwt.JsonWebTokenError);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when signing a token without jwt id', function() {
|
||||
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
|
||||
|
||||
it('should check jwt id', function() {
|
||||
jwt.verify(token, pub, { jwtid: 'jwtid' }, function(err, decoded) {
|
||||
assert.isUndefined(decoded);
|
||||
assert.isNotNull(err);
|
||||
assert.equal(err.name, 'JsonWebTokenError');
|
||||
assert.instanceOf(err, jwt.JsonWebTokenError);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when verifying a malformed token', function() {
|
||||
it('should throw', function(done) {
|
||||
jwt.verify('fruit.fruit.fruit', pub, function(err, decoded) {
|
||||
|
||||
Reference in New Issue
Block a user