Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ Error object:
* message:
* 'invalid token' - the header or payload could not be parsed
* 'jwt malformed' - the token does not have three components (delimited by a `.`)
* 'unsupported "crit" header parameter' - the token marks header parameters as critical ([RFC 7515 Section 4.1.11](https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.11)), which this library does not implement
* 'jwt signature is required'
* 'invalid signature'
* 'jwt audience invalid. expected: [OPTIONS AUDIENCE]'
Expand Down
85 changes: 85 additions & 0 deletions test/header-crit.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
'use strict';

const jwt = require('../');
const expect = require('chai').expect;
const util = require('util');
const testUtils = require('./test-utils');

function signWithCrit(crit, extraHeader) {
const header = Object.assign({}, extraHeader);
if (crit !== undefined) {
header.crit = crit;
}
return jwt.sign({sub: 'foo'}, 'secret', {algorithm: 'HS256', header});
}

describe('crit', function () {
describe('`jwt.verify` with a "crit" header parameter', function () {
[
// an extension nobody implements
['http://example.invalid/UNDEFINED'],
// RFC 7797 unencoded payload: a conformant verifier reads a different payload
['b64'],
// names the producer is not even allowed to mark critical
['alg'],
// shapes RFC 7515 forbids producers from emitting
[],
'b64',
1,
null,
{},
].forEach((crit) => {
it(`should error with value ${util.inspect(crit)}`, function (done) {
const token = signWithCrit(crit, {'http://example.invalid/UNDEFINED': true, b64: false});
testUtils.verifyJWTHelper(token, 'secret', {}, (err) => {
testUtils.asyncCheck(done, () => {
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
expect(err).to.have.property('message', 'unsupported "crit" header parameter');
});
});
});
});

it('should error before the "complete" option can expose the payload', function (done) {
const token = signWithCrit(['http://example.invalid/UNDEFINED']);
testUtils.verifyJWTHelper(token, 'secret', {complete: true}, (err, decoded) => {
testUtils.asyncCheck(done, () => {
expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
expect(err).to.have.property('message', 'unsupported "crit" header parameter');
expect(decoded).to.be.undefined;
});
});
});
});

describe('`jwt.verify` without a "crit" header parameter', function () {
it('should verify a token that has no "crit" header', function (done) {
const token = signWithCrit(undefined);
testUtils.verifyJWTHelper(token, 'secret', {}, (err, decoded) => {
testUtils.asyncCheck(done, () => {
expect(err).to.be.null;
expect(decoded).to.have.property('sub', 'foo');
});
});
});

it('should verify a token with unrecognized headers that are not marked critical', function (done) {
const token = signWithCrit(undefined, {'http://example.invalid/UNDEFINED': true});
testUtils.verifyJWTHelper(token, 'secret', {}, (err, decoded) => {
testUtils.asyncCheck(done, () => {
expect(err).to.be.null;
expect(decoded).to.have.property('sub', 'foo');
});
});
});
});

describe('`jwt.decode`', function () {
it('should still decode a token with a "crit" header, as it does not verify', function () {
const token = signWithCrit(['http://example.invalid/UNDEFINED']);
const decoded = jwt.decode(token, {complete: true});
expect(decoded.header).to.have.deep.property('crit', ['http://example.invalid/UNDEFINED']);
expect(decoded.payload).to.have.property('sub', 'foo');
});
});
});
8 changes: 8 additions & 0 deletions verify.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ module.exports = function (jwtString, secretOrPublicKey, options, callback) {
}

const header = decodedToken.header;

//RFC 7515 Section 4.1.11: "crit" lists extension header parameters that must be
//understood and processed, and the JWS is invalid if any of them are not. This
//library implements no such extension, so any "crit" header is unsupported.
if (typeof header.crit !== 'undefined') {
return done(new JsonWebTokenError('unsupported "crit" header parameter'));
}

let getSecret;

if(typeof secretOrPublicKey === 'function') {
Expand Down