Repository: auth0/auth0.js
Pull request #324 (2017-01-18 20:13:57)

Fixed params whitelist for authorize endpoint
Related to https://github.com/auth0/lock/issues/818


Patch:
diff --git a/src/authentication/index.js b/src/authentication/index.js
index 352c4f5..95361b7 100644
--- a/src/authentication/index.js
+++ b/src/authentication/index.js
@@ -101,7 +101,7 @@ Authentication.prototype.buildAuthorizeUrl = function (options) {
   }
 
   params = objectHelper.toSnakeCase(params, ['auth0Client']);
-  params = parametersWhitelist.oauthAuthorizeParams(params);
+  params = parametersWhitelist.oauthAuthorizeParams(this.warn, params);
 
   qString = qs.build(params);
 
@@ -220,7 +220,7 @@ Authentication.prototype.oauthToken = function (options, cb) {
   });
 
   body = objectHelper.toSnakeCase(body, ['auth0Client']);
-  body = parametersWhitelist.oauthTokenParams(body);
+  body = parametersWhitelist.oauthTokenParams(this.warn, body);
 
   body.grant_type = body.grant_type;
 
diff --git a/src/helper/object.js b/src/helper/object.js
index 1858469..bc6cb97 100644
--- a/src/helper/object.js
+++ b/src/helper/object.js
@@ -14,6 +14,16 @@ function pick(object, keys) {
   }, {});
 }
 
+function getKeysNotIn(obj, allowedKeys) {
+  var notAllowed = [];
+  for (var key in obj) {
+    if (allowedKeys.indexOf(key) === -1) {
+      notAllowed.push(key);
+    }
+  }
+  return notAllowed;
+}
+
 function objectValues(obj) {
   var values = [];
   for (var key in obj) {
@@ -111,5 +121,6 @@ module.exports = {
   blacklist: blacklist,
   merge: merge,
   pick: pick,
+  getKeysNotIn: getKeysNotIn,
   extend: extend
 };
diff --git a/src/helper/parameters-whitelist.js b/src/helper/parameters-whitelist.js
index 99ebc14..c7d23e4 100644
--- a/src/helper/parameters-whitelist.js
+++ b/src/helper/parameters-whitelist.js
@@ -1,4 +1,4 @@
-var objectHelper = require('../helper/object');
+var objectHelper = require('./object');
 
 var tokenParams = [
 // auth0
@@ -27,6 +27,11 @@ var authorizeParams = [
   'auth0Client',
   'owp',
   'device',
+
+  'protocol',
+  '_csrf',
+  '_intstate',
+
 // oauth2
   'client_id',
   'response_type',
@@ -52,11 +57,17 @@ var authorizeParams = [
   'code_challenge_method'
 ];
 
-function oauthAuthorizeParams(params) {
-  return objectHelper.pick(params, authorizeParams);
+function oauthAuthorizeParams(warn, params) {
+  var notAllowed = objectHelper.getKeysNotIn(params, authorizeParams);
+
+  if (notAllowed.length > 0) {
+    warn.warning('Following parameters are not allowed on the `/authorize` endpoing: [' + notAllowed.join(',') + ']');
+  }
+
+  return params;
 }
 
-function oauthTokenParams(params) {
+function oauthTokenParams(warn, params) {
   return objectHelper.pick(params, tokenParams);
 }
 
diff --git a/src/version.js b/src/version.js
index 5c92af4..31ba773 100644
--- a/src/version.js
+++ b/src/version.js
@@ -1,1 +1,1 @@
-module.exports = { raw:'8.1.1' };
+module.exports = { raw: '8.1.1' };


Test patch:
diff --git a/test/authentication/authentication.test.js b/test/authentication/authentication.test.js
index 077d1e9..10130e5 100644
--- a/test/authentication/authentication.test.js
+++ b/test/authentication/authentication.test.js
@@ -74,7 +74,7 @@ describe('auth0.authentication', function () {
         connection_scope: 'scope1,scope2'
       });
 
-      expect(url).to.be('https://me.auth0.com/authorize?connection_scope=scope1%2Cscope2&client_id=...&response_type=token&redirect_uri=http%3A%2F%2Fanotherpage.com%2Fcallback2&state=1234&prompt=none');
+      expect(url).to.be('https://me.auth0.com/authorize?client_id=...&response_type=token&redirect_uri=http%3A%2F%2Fanotherpage.com%2Fcallback2&prompt=none&state=1234&connection_scope=scope1%2Cscope2');
     })
 
     it('should return a url with connection_scope as a string', function() {
@@ -86,7 +86,7 @@ describe('auth0.authentication', function () {
         connection_scope: ['scope1', 'scope2']
       });
 
-      expect(url).to.be('https://me.auth0.com/authorize?connection_scope=scope1%2Cscope2&client_id=...&response_type=token&redirect_uri=http%3A%2F%2Fanotherpage.com%2Fcallback2&state=1234&prompt=none');
+      expect(url).to.be('https://me.auth0.com/authorize?client_id=...&response_type=token&redirect_uri=http%3A%2F%2Fanotherpage.com%2Fcallback2&prompt=none&state=1234&connection_scope=scope1%2Cscope2');
     })
 
     it('should return a url using overriding the default settings', function() {
@@ -97,7 +97,7 @@ describe('auth0.authentication', function () {
         state: '1234'
       });
 
-      expect(url).to.be('https://me.auth0.com/authorize?client_id=...&response_type=token&redirect_uri=http%3A%2F%2Fanotherpage.com%2Fcallback2&state=1234&prompt=none');
+      expect(url).to.be('https://me.auth0.com/authorize?client_id=...&response_type=token&redirect_uri=http%3A%2F%2Fanotherpage.com%2Fcallback2&prompt=none&state=1234');
     })
 
     it('should return a url using using whitelisted authorization parameter device', function() {
@@ -109,7 +109,7 @@ describe('auth0.authentication', function () {
         device: 'my-device'
       });
 
-      expect(url).to.be('https://me.auth0.com/authorize?device=my-device&client_id=...&response_type=token&redirect_uri=http%3A%2F%2Fanotherpage.com%2Fcallback2&state=1234&prompt=none');
+      expect(url).to.be('https://me.auth0.com/authorize?client_id=...&response_type=token&redirect_uri=http%3A%2F%2Fanotherpage.com%2Fcallback2&prompt=none&state=1234&device=my-device');
     })
   })
 
@@ -131,7 +131,7 @@ describe('auth0.authentication', function () {
         state: '1234'
       });
 
-      expect(url).to.be('https://me.auth0.com/authorize?auth0Client='+ encodeURIComponent(telemetryInfo) +'&client_id=...&response_type=token&redirect_uri=http%3A%2F%2Fanotherpage.com%2Fcallback2&state=1234&prompt=none');
+      expect(url).to.be('https://me.auth0.com/authorize?client_id=...&response_type=token&redirect_uri=http%3A%2F%2Fanotherpage.com%2Fcallback2&prompt=none&state=1234&auth0Client='+ encodeURIComponent(telemetryInfo));
     })
   })
 
diff --git a/test/helper/object.test.js b/test/helper/object.test.js
index 730202e..794d3cf 100644
--- a/test/helper/object.test.js
+++ b/test/helper/object.test.js
@@ -5,6 +5,63 @@ var objectAssign = require('../../src/helper/object-assign');
 var objectHelper = require('../../src/helper/object');
 
 describe('helpers', function () {
+  describe('getKeysNotIn', function () {
+    it('should return the list of keys not allowed', function () {
+      var object = {
+        attr1: 'attribute_1',
+        attr2: 'attribute_2',
+        attr3: 'attribute_3'
+      };
+
+      var notAllowed = ['attr1','attr2','attr4'];
+
+      var keysList = objectHelper.getKeysNotIn(object, notAllowed);
+
+      expect(keysList).to.eql(['attr3'])
+
+    });
+
+    it('should return an empty list', function () {
+      var object = {
+        attr1: 'attribute_1',
+        attr2: 'attribute_2',
+        attr3: 'attribute_3'
+      };
+
+      var notAllowed = ['attr1','attr2','attr3'];
+
+      var keysList = objectHelper.getKeysNotIn(object, notAllowed);
+
+      expect(keysList).to.eql([])
+
+    });
+
+    it('should return an all the keys', function () {
+      var object = {
+        attr1: 'attribute_1',
+        attr2: 'attribute_2',
+        attr3: 'attribute_3'
+      };
+
+      var notAllowed = ['attr5','attr6','attr7'];
+
+      var keysList = objectHelper.getKeysNotIn(object, notAllowed);
+
+      expect(keysList).to.eql(['attr1','attr2','attr3'])
+    });
+
+    it('should return another empty list', function () {
+      var object = {
+      };
+
+      var notAllowed = ['attr5','attr6','attr7'];
+
+      var keysList = objectHelper.getKeysNotIn(object, notAllowed);
+
+      expect(keysList).to.eql([])
+    });
+  });
+
   describe('pick', function () {
     it('should return only the requested attributes', function () {
       var object = {
diff --git a/test/web-auth/popup.test.js b/test/web-auth/popup.test.js
index 0f80859..6b1a7bc 100644
--- a/test/web-auth/popup.test.js
+++ b/test/web-auth/popup.test.js
@@ -85,7 +85,7 @@ describe('auth0.WebAuth.popup', function () {
 
     it('should open the authorize page in a popup', function (done) {
       stub(PopupHandler.prototype, 'load', function(url, relayUrl, options, cb) {
-        expect(url).to.be('https://me.auth0.com/authorize?connection=the_connection&owp=true&client_id=...&response_type=id_token&redirect_uri=http%3A%2F%2Fpage.com%2Fcallback&state=456&nonce=123');
+        expect(url).to.be('https://me.auth0.com/authorize?client_id=...&response_type=id_token&redirect_uri=http%3A%2F%2Fpage.com%2Fcallback&connection=the_connection&nonce=123&state=456&owp=true');
         expect(relayUrl).to.be('https://me.auth0.com/relay.html');
         expect(options).to.eql({});
         cb(null, {
diff --git a/test/web-auth/redirect.test.js b/test/web-auth/redirect.test.js
index 3a08519..9840f56 100644
--- a/test/web-auth/redirect.test.js
+++ b/test/web-auth/redirect.test.js
@@ -561,7 +561,7 @@ describe('auth0.WebAuth.redirect', function () {
 
     it('should redirect to authorize', function () {
       this.auth0.authorize({responseType: 'code', connection: 'facebook', state: '1234'})
-      expect(global.window.location).to.be('https://me.auth0.com/authorize?connection=facebook&client_id=...&response_type=code&redirect_uri=http%3A%2F%2Fpage.com%2Fcallback&state=1234');
+      expect(global.window.location).to.be('https://me.auth0.com/authorize?client_id=...&redirect_uri=http%3A%2F%2Fpage.com%2Fcallback&response_type=code&connection=facebook&state=1234');
     });
 
     it('should redirect to logout', function () {
diff --git a/test/web-auth/web-auth.test.js b/test/web-auth/web-auth.test.js
index f48980d..037c4cd 100644
--- a/test/web-auth/web-auth.test.js
+++ b/test/web-auth/web-auth.test.js
@@ -282,7 +282,7 @@ describe('auth0.WebAuth', function () {
 
     it('should pass the correct authorize url', function (done) {
       stub(IframeHandler.prototype, 'init', function(message) {
-        expect(this.url).to.be('https://me.auth0.com/authorize?client_id=...&response_type=id_token&response_mode=fragment&redirect_uri=http%3A%2F%2Fpage.com%2Fcallback&audience=urn%3Asite%3Ademo%3Ablog&scope=openid%20name%20read%3Ablog&state=456&nonce=123&prompt=none');
+        expect(this.url).to.be('https://me.auth0.com/authorize?client_id=...&response_type=id_token&redirect_uri=http%3A%2F%2Fpage.com%2Fcallback&scope=openid%20name%20read%3Ablog&audience=urn%3Asite%3Ademo%3Ablog&nonce=123&state=456&response_mode=fragment&prompt=none');
         this.timeoutCallback();
       });