From 4c6c905b2d19316ed86c9dd14c09277c9053b900 Mon Sep 17 00:00:00 2001 From: "Alessandro (Ale) Segala" <43508+ItalyPaleAle@users.noreply.github.com> Date: Mon, 16 Mar 2020 00:41:12 -0700 Subject: [PATCH 1/4] issuer option can be a callback --- src/index.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 911f373..401fbdd 100644 --- a/src/index.js +++ b/src/index.js @@ -13,12 +13,24 @@ var isNumber = n => typeof n === 'number'; var defaultClock = () => new Date(); var DEFAULT_LEEWAY = 60; +/** + * This callback is a function that accepts the decoded (but not yet validated) + * payload from the id_token, and returns the expected value for the + * `iss` claim in the id_token. + * It can be used to validate certain id_token's, such as those returned by + * Azure AD when in multi-tenant mode. + * @callback IssuerCallback + * @param {Object} payload the payload of the id_token (decoded but not yet validated) + * @returns {string} the expected value for the `iss` claim in the id_token + */ + /** * Creates a new id_token verifier * @constructor * @param {Object} parameters - * @param {String} parameters.issuer name of the issuer of the token - * that should match the `iss` claim in the id_token + * @param {String|IssuerCallback} parameters.issuer name of the issuer of the token + * that should match the `iss` claim in the id_token, or a callback + * that returns the expected value * @param {String} parameters.audience identifies the recipients that the JWT is intended for * and should match the `aud` claim * @param {Object} [parameters.jwksCache] cache for JSON Web Token Keys. By default it has no cache @@ -148,11 +160,11 @@ IdTokenVerifier.prototype.verify = function(token, requestedNonce, cb) { ); } - if (_this.issuer !== iss) { + if ((typeof _this.issuer == 'function' && _this.issuer(jwt.payload) !== iss) || (typeof _this.issuer != 'function' && _this.issuer !== iss)) { return cb( new error.TokenValidationError( 'Issuer (iss) claim mismatch in the ID token, expected "' + - _this.issuer + + (typeof _this.issuer == 'function' ? _this.issuer(jwt.payload) : _this.issuer) + '", found "' + iss + '"' From 332767b511c4f6a28dcb49058e69fe90c0b1a22d Mon Sep 17 00:00:00 2001 From: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com> Date: Mon, 16 Mar 2020 08:47:50 -0700 Subject: [PATCH 2/4] Cached value as requested --- src/index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 401fbdd..c144a77 100644 --- a/src/index.js +++ b/src/index.js @@ -160,11 +160,15 @@ IdTokenVerifier.prototype.verify = function(token, requestedNonce, cb) { ); } - if ((typeof _this.issuer == 'function' && _this.issuer(jwt.payload) !== iss) || (typeof _this.issuer != 'function' && _this.issuer !== iss)) { + const expectIss = + typeof _this.issuer == 'function' + ? _this.issuer(jwt.payload) + : _this.issuer; + if (expectIss !== iss) { return cb( new error.TokenValidationError( 'Issuer (iss) claim mismatch in the ID token, expected "' + - (typeof _this.issuer == 'function' ? _this.issuer(jwt.payload) : _this.issuer) + + expectIss + '", found "' + iss + '"' From de93483ca04811fc5b81fe7bece08274de4213a7 Mon Sep 17 00:00:00 2001 From: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com> Date: Mon, 16 Mar 2020 08:58:52 -0700 Subject: [PATCH 3/4] Added tests --- test/helper/jwt.js | 3 +++ test/token-verification.test.js | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/test/helper/jwt.js b/test/helper/jwt.js index 68d3706..2064e2f 100644 --- a/test/helper/jwt.js +++ b/test/helper/jwt.js @@ -44,6 +44,9 @@ export const createJWT = ( options = DEFAULT_OPTIONS ) => { return createCertificate().then(cert => { + if (typeof options.issuer == 'function') { + options.issuer = options.issuer(DEFAULT_PAYLOAD); + } return jwt.sign(payload, cert.serviceKey, { algorithm: 'RS256', keyid: 'QzE4N0ZBM0VDQzE2RUU0NzI1QzY1MzQ4QTk1MzAwMEI4RDgxNzE4Rg', diff --git a/test/token-verification.test.js b/test/token-verification.test.js index 5d3d48a..47c7aa5 100644 --- a/test/token-verification.test.js +++ b/test/token-verification.test.js @@ -193,6 +193,26 @@ describe('jwt-verification', function() { .catch(done); }); + it('validates issuer as function', done => { + const options = Object.assign({}, DEFAULT_OPTIONS, { + issuer: function(payload) { + return '__ANOTHER_ISSUER__'; + } + }); + + createJWT(DEFAULT_PAYLOAD, options) + .then(token => { + helpers.assertTokenValidationError( + DEFAULT_CONFIG, + 'asfd', + `Issuer (iss) claim mismatch in the ID token, expected "__TEST_ISSUER__", found "__ANOTHER_ISSUER__"`, + token, + done + ); + }) + .catch(done); + }); + it('validates presence of subject in the token', done => { const { sub, ...payload } = DEFAULT_PAYLOAD; From 871f8fb628322a880eb11d1e72f9ec4b80bfa3d5 Mon Sep 17 00:00:00 2001 From: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com> Date: Mon, 16 Mar 2020 08:59:53 -0700 Subject: [PATCH 4/4] Docs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a5cbd47..3d34dca 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Initializes the verifier. Parameters: - configuration - - issuer: the issuer you trust to sign the tokens. + - issuer: the issuer you trust to sign the tokens, or a function that returns the value (the function takes one argument with the full payload of the token, decoded but not yet validated) - audience: the audience the token is issued for. - leeway: when there is a clock skew times between the signing and verifying servers. The leeway should not be bigger than five minutes. - jwksCache: the verifier will try to fetch the JWKS from the `/.well-known/jwks.json` endpoint (or `jwksURI` if provided) each time it verifies a token. You can provide a cache to store the keys and avoid repeated requests. For the contract, check [this example](https://github.com/auth0/jwt-js-rsa-verification/blob/master/src/helpers/dummy-cache.js). Hint: for in-memory cache, an easy way is to just provide `new Map()`, which is a valid object for jwksCache.