mirror of
https://github.com/hanzoai/node-jsonwebtoken.git
synced 2026-09-24 17:00:48 +00:00
* fix(sign&verify)!: Remove default none support from sign and verify methods, and require it to be explicitly configured BREAKING CHANGE: Removes fallback for none algorithm for the verify method.
437 lines
17 KiB
JavaScript
437 lines
17 KiB
JavaScript
'use strict';
|
|
|
|
const jwt = require('../');
|
|
const expect = require('chai').expect;
|
|
const util = require('util');
|
|
const testUtils = require('./test-utils');
|
|
|
|
function signWithAudience(audience, payload, callback) {
|
|
const options = {algorithm: 'HS256'};
|
|
if (audience !== undefined) {
|
|
options.audience = audience;
|
|
}
|
|
|
|
testUtils.signJWTHelper(payload, 'secret', options, callback);
|
|
}
|
|
|
|
function verifyWithAudience(token, audience, callback) {
|
|
testUtils.verifyJWTHelper(token, 'secret', {audience}, callback);
|
|
}
|
|
|
|
describe('audience', function() {
|
|
describe('`jwt.sign` "audience" option validation', function () {
|
|
[
|
|
true,
|
|
false,
|
|
null,
|
|
-1,
|
|
1,
|
|
0,
|
|
-1.1,
|
|
1.1,
|
|
-Infinity,
|
|
Infinity,
|
|
NaN,
|
|
{},
|
|
{foo: 'bar'},
|
|
].forEach((audience) => {
|
|
it(`should error with with value ${util.inspect(audience)}`, function (done) {
|
|
signWithAudience(audience, {}, (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(Error);
|
|
expect(err).to.have.property('message', '"audience" must be a string or array');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
// undefined needs special treatment because {} is not the same as {aud: undefined}
|
|
it('should error with with value undefined', function (done) {
|
|
testUtils.signJWTHelper({}, 'secret', {audience: undefined, algorithm: 'HS256'}, (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(Error);
|
|
expect(err).to.have.property('message', '"audience" must be a string or array');
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error when "aud" is in payload', function (done) {
|
|
signWithAudience('my_aud', {aud: ''}, (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(Error);
|
|
expect(err).to.have.property(
|
|
'message',
|
|
'Bad "options.audience" option. The payload already has an "aud" property.'
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error with a string payload', function (done) {
|
|
signWithAudience('my_aud', 'a string payload', (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(Error);
|
|
expect(err).to.have.property('message', 'invalid audience option for string payload');
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error with a Buffer payload', function (done) {
|
|
signWithAudience('my_aud', new Buffer('a Buffer payload'), (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(Error);
|
|
expect(err).to.have.property('message', 'invalid audience option for object payload');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('when signing and verifying a token with "audience" option', function () {
|
|
describe('with a "aud" of "urn:foo" in payload', function () {
|
|
let token;
|
|
|
|
beforeEach(function (done) {
|
|
signWithAudience('urn:foo', {}, (err, t) => {
|
|
token = t;
|
|
done(err);
|
|
});
|
|
});
|
|
|
|
[
|
|
undefined,
|
|
'urn:foo',
|
|
/^urn:f[o]{2}$/,
|
|
['urn:no_match', 'urn:foo'],
|
|
['urn:no_match', /^urn:f[o]{2}$/],
|
|
[/^urn:no_match$/, /^urn:f[o]{2}$/],
|
|
[/^urn:no_match$/, 'urn:foo']
|
|
].forEach((audience) =>{
|
|
it(`should verify and decode with verify "audience" option of ${util.inspect(audience)}`, function (done) {
|
|
verifyWithAudience(token, audience, (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud', 'urn:foo');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
it(`should error on no match with a string verify "audience" option`, function (done) {
|
|
verifyWithAudience(token, 'urn:no-match', (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property('message', `jwt audience invalid. expected: urn:no-match`);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with an array of string verify "audience" option', function (done) {
|
|
verifyWithAudience(token, ['urn:no-match-1', 'urn:no-match-2'], (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property('message', `jwt audience invalid. expected: urn:no-match-1 or urn:no-match-2`);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with a Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, /^urn:no-match$/, (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property('message', `jwt audience invalid. expected: /^urn:no-match$/`);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with an array of Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, [/^urn:no-match-1$/, /^urn:no-match-2$/], (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property(
|
|
'message', `jwt audience invalid. expected: /^urn:no-match-1$/ or /^urn:no-match-2$/`
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with an array of a Regex and a string in verify "audience" option', function (done) {
|
|
verifyWithAudience(token, [/^urn:no-match$/, 'urn:no-match'], (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property(
|
|
'message', `jwt audience invalid. expected: /^urn:no-match$/ or urn:no-match`
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('with an array of ["urn:foo", "urn:bar"] for "aud" value in payload', function () {
|
|
let token;
|
|
|
|
beforeEach(function (done) {
|
|
signWithAudience(['urn:foo', 'urn:bar'], {}, (err, t) => {
|
|
token = t;
|
|
done(err);
|
|
});
|
|
});
|
|
|
|
[
|
|
undefined,
|
|
'urn:foo',
|
|
/^urn:f[o]{2}$/,
|
|
['urn:no_match', 'urn:foo'],
|
|
['urn:no_match', /^urn:f[o]{2}$/],
|
|
[/^urn:no_match$/, /^urn:f[o]{2}$/],
|
|
[/^urn:no_match$/, 'urn:foo']
|
|
].forEach((audience) =>{
|
|
it(`should verify and decode with verify "audience" option of ${util.inspect(audience)}`, function (done) {
|
|
verifyWithAudience(token, audience, (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
it(`should error on no match with a string verify "audience" option`, function (done) {
|
|
verifyWithAudience(token, 'urn:no-match', (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property('message', `jwt audience invalid. expected: urn:no-match`);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with an array of string verify "audience" option', function (done) {
|
|
verifyWithAudience(token, ['urn:no-match-1', 'urn:no-match-2'], (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property('message', `jwt audience invalid. expected: urn:no-match-1 or urn:no-match-2`);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with a Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, /^urn:no-match$/, (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property('message', `jwt audience invalid. expected: /^urn:no-match$/`);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with an array of Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, [/^urn:no-match-1$/, /^urn:no-match-2$/], (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property(
|
|
'message', `jwt audience invalid. expected: /^urn:no-match-1$/ or /^urn:no-match-2$/`
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with an array of a Regex and a string in verify "audience" option', function (done) {
|
|
verifyWithAudience(token, [/^urn:no-match$/, 'urn:no-match'], (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property(
|
|
'message', `jwt audience invalid. expected: /^urn:no-match$/ or urn:no-match`
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('when checking for a matching on both "urn:foo" and "urn:bar"', function() {
|
|
it('should verify with an array of stings verify "audience" option', function (done) {
|
|
verifyWithAudience(token, ['urn:foo', 'urn:bar'], (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should verify with a Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, /^urn:[a-z]{3}$/, (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should verify with an array of Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, [/^urn:f[o]{2}$/, /^urn:b[ar]{2}$/], (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('when checking for a matching for "urn:foo"', function() {
|
|
it('should verify with a string verify "audience"', function (done) {
|
|
verifyWithAudience(token, 'urn:foo', (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should verify with a Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, /^urn:f[o]{2}$/, (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should verify with an array of Regex verify "audience"', function (done) {
|
|
verifyWithAudience(token, [/^urn:no-match$/, /^urn:f[o]{2}$/], (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should verify with an array containing a string and a Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, ['urn:no_match', /^urn:f[o]{2}$/], (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should verify with an array containing a Regex and a string verify "audience" option', function (done) {
|
|
verifyWithAudience(token, [/^urn:no-match$/, 'urn:foo'], (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('when checking matching for "urn:bar"', function() {
|
|
it('should verify with a string verify "audience"', function (done) {
|
|
verifyWithAudience(token, 'urn:bar', (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should verify with a Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, /^urn:b[ar]{2}$/, (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should verify with an array of Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, [/^urn:no-match$/, /^urn:b[ar]{2}$/], (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should verify with an array containing a string and a Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, ['urn:no_match', /^urn:b[ar]{2}$/], (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should verify with an array containing a Regex and a string verify "audience" option', function (done) {
|
|
verifyWithAudience(token, [/^urn:no-match$/, 'urn:bar'], (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('without a "aud" value in payload', function () {
|
|
let token;
|
|
|
|
beforeEach(function (done) {
|
|
signWithAudience(undefined, {}, (err, t) => {
|
|
token = t;
|
|
done(err);
|
|
});
|
|
});
|
|
|
|
it('should verify and decode without verify "audience" option', function (done) {
|
|
verifyWithAudience(token, undefined, (err, decoded) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.null;
|
|
expect(decoded).to.not.have.property('aud');
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with a string verify "audience" option', function (done) {
|
|
verifyWithAudience(token, 'urn:no-match', (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property('message', 'jwt audience invalid. expected: urn:no-match');
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with an array of string verify "audience" option', function (done) {
|
|
verifyWithAudience(token, ['urn:no-match-1', 'urn:no-match-2'], (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property('message', 'jwt audience invalid. expected: urn:no-match-1 or urn:no-match-2');
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with a Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, /^urn:no-match$/, (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property('message', 'jwt audience invalid. expected: /^urn:no-match$/');
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with an array of Regex verify "audience" option', function (done) {
|
|
verifyWithAudience(token, [/^urn:no-match-1$/, /^urn:no-match-2$/], (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property('message', 'jwt audience invalid. expected: /^urn:no-match-1$/ or /^urn:no-match-2$/');
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should error on no match with an array of a Regex and a string in verify "audience" option', function (done) {
|
|
verifyWithAudience(token, [/^urn:no-match$/, 'urn:no-match'], (err) => {
|
|
testUtils.asyncCheck(done, () => {
|
|
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
|
|
expect(err).to.have.property('message', 'jwt audience invalid. expected: /^urn:no-match$/ or urn:no-match');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|